koffi 2.16.1 → 3.0.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/CHANGELOG.md +2 -2
  2. package/README.md +8 -8
  3. package/build/koffi/darwin_arm64/koffi.node +0 -0
  4. package/build/koffi/darwin_x64/koffi.node +0 -0
  5. package/build/koffi/freebsd_arm64/koffi.node +0 -0
  6. package/build/koffi/freebsd_ia32/koffi.node +0 -0
  7. package/build/koffi/freebsd_x64/koffi.node +0 -0
  8. package/build/koffi/linux_arm64/koffi.node +0 -0
  9. package/build/koffi/linux_ia32/koffi.node +0 -0
  10. package/build/koffi/linux_x64/koffi.node +0 -0
  11. package/build/koffi/musl_arm64/koffi.node +0 -0
  12. package/build/koffi/musl_x64/koffi.node +0 -0
  13. package/build/koffi/openbsd_ia32/koffi.node +0 -0
  14. package/build/koffi/openbsd_x64/koffi.node +0 -0
  15. package/build/koffi/win32_ia32/koffi.node +0 -0
  16. package/build/koffi/win32_x64/koffi.node +0 -0
  17. package/doc/benchmarks.md +33 -33
  18. package/doc/benchmarks.xlsx +0 -0
  19. package/doc/contribute.md +37 -25
  20. package/doc/index.md +8 -8
  21. package/doc/variables.md +1 -1
  22. package/index.d.ts +11 -9
  23. package/index.js +1 -634
  24. package/indirect.js +1 -533
  25. package/lib/native/base/base.cc +63 -85
  26. package/lib/native/base/base.hh +178 -151
  27. package/package.json +3 -4
  28. package/src/build.js +1178 -0
  29. package/src/koffi/CMakeLists.txt +97 -34
  30. package/src/koffi/index.js +359 -0
  31. package/src/koffi/indirect.js +216 -0
  32. package/src/koffi/src/{abi_arm32.cc → abi/arm32.cc} +279 -275
  33. package/src/koffi/src/{abi_arm32_asm.S → abi/arm32_asm.S} +2 -5
  34. package/src/koffi/src/abi/arm64.cc +1511 -0
  35. package/src/koffi/src/{abi_arm64_asm.S → abi/arm64_asm.S} +44 -23
  36. package/src/koffi/src/{abi_arm64_asm.asm → abi/arm64_asm.asm} +32 -25
  37. package/src/koffi/src/{abi_loong64_asm.S → abi/loong64_asm.S} +1 -5
  38. package/src/koffi/src/{abi_riscv64.cc → abi/riscv64.cc} +279 -273
  39. package/src/koffi/src/{abi_riscv64_asm.S → abi/riscv64_asm.S} +1 -4
  40. package/src/koffi/src/abi/x64sysv.cc +1456 -0
  41. package/src/koffi/src/{abi_x64_sysv_asm.S → abi/x64sysv_asm.S} +30 -33
  42. package/src/koffi/src/abi/x64win.cc +1121 -0
  43. package/src/koffi/src/{abi_x64_win_asm.S → abi/x64win_asm.S} +8 -12
  44. package/src/koffi/src/{abi_x64_win_asm.asm → abi/x64win_asm.asm} +11 -14
  45. package/src/koffi/src/abi/x86.cc +1233 -0
  46. package/src/koffi/src/{abi_x86_asm.S → abi/x86_asm.S} +49 -25
  47. package/src/koffi/src/{abi_x86_asm.asm → abi/x86_asm.asm} +11 -14
  48. package/src/koffi/src/call.cc +458 -598
  49. package/src/koffi/src/call.hh +61 -82
  50. package/src/koffi/src/ffi.cc +595 -309
  51. package/src/koffi/src/ffi.hh +103 -89
  52. package/src/koffi/src/parser.cc +0 -4
  53. package/src/koffi/src/primitives.inc +39 -0
  54. package/src/koffi/{tools/write_trampolines.js → src/trampolines.js} +1 -1
  55. package/src/koffi/src/util.cc +503 -446
  56. package/src/koffi/src/util.hh +269 -57
  57. package/src/koffi/src/uv.cc +2 -2
  58. package/src/koffi/src/uv.def +3 -0
  59. package/src/koffi/src/win32.hh +30 -1
  60. package/vendor/node-addon-api/napi-inl.h +4 -0
  61. package/vendor/node-addon-api/napi.h +1 -0
  62. package/build/koffi/linux_armhf/koffi.node +0 -0
  63. package/build/koffi/linux_loong64/koffi.node +0 -0
  64. package/build/koffi/linux_riscv64d/koffi.node +0 -0
  65. package/build/koffi/win32_arm64/koffi.exp +0 -0
  66. package/build/koffi/win32_arm64/koffi.lib +0 -0
  67. package/build/koffi/win32_arm64/koffi.node +0 -0
  68. package/doc/platforms.md +0 -36
  69. package/src/cnoke/LICENSE.txt +0 -22
  70. package/src/cnoke/README.md +0 -99
  71. package/src/cnoke/assets/FindCNoke.cmake +0 -127
  72. package/src/cnoke/assets/toolchains.json +0 -126
  73. package/src/cnoke/assets/win_delay_hook.c +0 -36
  74. package/src/cnoke/cnoke.js +0 -170
  75. package/src/cnoke/package.json +0 -24
  76. package/src/cnoke/src/builder.js +0 -511
  77. package/src/cnoke/src/index.js +0 -10
  78. package/src/cnoke/src/tools.js +0 -407
  79. package/src/koffi/src/abi_arm64.cc +0 -1295
  80. package/src/koffi/src/abi_x64_sysv.cc +0 -939
  81. package/src/koffi/src/abi_x64_win.cc +0 -715
  82. package/src/koffi/src/abi_x86.cc +0 -860
  83. package/src/koffi/src/init.js +0 -105
  84. /package/src/koffi/src/{abi_loong64.cc → abi/loong64.cc} +0 -0
@@ -22,66 +22,15 @@ static const Size MaxParameters = 64;
22
22
  static const Size MaxTrampolines = 8192;
23
23
 
24
24
  enum class PrimitiveKind {
25
- // Void is explictly not first so that it is not 0, for reasons related to N-API type tags.
26
- // Look at TypeInfo definition for more information!
27
- Bool,
28
- Void,
29
- Int8,
30
- UInt8,
31
- Int16,
32
- Int16S, // Keep behind Int16
33
- UInt16,
34
- UInt16S, // Keep behind UInt16
35
- Int32,
36
- Int32S, // Keep behind Int32
37
- UInt32,
38
- UInt32S, // Keep behind UInt32
39
- Int64,
40
- Int64S, // Keep behind Int64
41
- UInt64,
42
- UInt64S, // Keep behind UInt64
43
- String,
44
- String16,
45
- String32,
46
- Pointer,
47
- Record,
48
- Union,
49
- Array,
50
- Float32,
51
- Float64,
52
- Prototype,
53
- Callback
25
+ #define PRIMITIVE(Name) Name,
26
+ #include "primitives.inc"
54
27
  };
55
28
  static const char *const PrimitiveKindNames[] = {
56
- "Bool",
57
- "Void",
58
- "Int8",
59
- "UInt8",
60
- "Int16",
61
- "Int16S",
62
- "UInt16",
63
- "UInt16S",
64
- "Int32",
65
- "Int32S",
66
- "UInt32",
67
- "UInt32S",
68
- "Int64",
69
- "Int64S",
70
- "UInt64",
71
- "UInt64S",
72
- "String",
73
- "String16",
74
- "String32",
75
- "Pointer",
76
- "Record",
77
- "Union",
78
- "Array",
79
- "Float32",
80
- "Float64",
81
- "Prototype",
82
- "Callback"
29
+ #define PRIMITIVE(Name) K_STRINGIFY(Name),
30
+ #include "primitives.inc"
83
31
  };
84
32
 
33
+ struct InstanceData;
85
34
  struct TypeInfo;
86
35
  struct RecordMember;
87
36
  struct FunctionInfo;
@@ -109,7 +58,7 @@ static const char *const ArrayHintNames[] = {
109
58
  struct TypeInfo {
110
59
  const char *name;
111
60
 
112
- // Make sure primitie ends up as the upper N-API tag value when we cast TypeInfo pointers to
61
+ // Make sure primitive ends up as the upper N-API tag value when we cast TypeInfo pointers to
113
62
  // napi_type_tag pointers. Yes, I want to do this. We don't do strict aliasing here.
114
63
  // N.B. Some node versions don't like when one of the two tag values is 0, so make sure
115
64
  // this does not happen! It would happen if primitive is 0 and size is 0. To avoid this
@@ -124,7 +73,6 @@ struct TypeInfo {
124
73
 
125
74
  HeapArray<RecordMember> members; // Record only
126
75
  union {
127
- const void *marker;
128
76
  const TypeInfo *type; // Pointer or array
129
77
  const FunctionInfo *proto; // Callback only
130
78
  } ref;
@@ -139,6 +87,7 @@ struct TypeInfo {
139
87
 
140
88
  struct RecordMember {
141
89
  const char *name;
90
+ napi_ref key;
142
91
  const TypeInfo *type;
143
92
  int32_t offset;
144
93
  Size countedby;
@@ -170,6 +119,16 @@ static const char *const CallConventionNames[] = {
170
119
  "Thiscall"
171
120
  };
172
121
 
122
+ enum class AbiMethod : int;
123
+
124
+ struct AbiInstruction {
125
+ void *op;
126
+ int32_t a;
127
+ int16_t b1;
128
+ int16_t b2;
129
+ const TypeInfo *type;
130
+ };
131
+
173
132
  struct ParameterInfo {
174
133
  const TypeInfo *type;
175
134
  int directions;
@@ -179,20 +138,47 @@ struct ParameterInfo {
179
138
  // ABI-specific part
180
139
 
181
140
  #if defined(_M_X64)
182
- bool regular;
141
+ bool regular; // Used for structs and unions
183
142
  #elif defined(__x86_64__)
184
- bool use_memory;
185
- int8_t gpr_count;
186
- int8_t xmm_count;
187
- bool gpr_first;
143
+ struct {
144
+ bool regular;
145
+ int offsets[2];
146
+ } abi;
188
147
  #elif defined(__arm__) || defined(__aarch64__) || defined(_M_ARM64)
189
- bool use_memory; // Only used for return value on ARM32
148
+ struct {
149
+ bool regular;
150
+ bool indirect;
151
+ int hfa32;
152
+ int offset;
153
+ } abi;
154
+ #elif __riscv_xlen == 64 || defined(__loongarch64)
155
+ bool use_memory;
190
156
  int8_t gpr_count;
191
157
  int8_t vec_count;
192
- int8_t vec_bytes; // ARM64
158
+ bool gpr_first; // Only for structs
159
+ int8_t reg_size[2];
160
+ #endif
161
+ };
162
+
163
+ struct ReturnInfo {
164
+ const TypeInfo *type;
165
+
166
+ // ABI-specific part
167
+
168
+ #if defined(_M_X64)
169
+ bool regular;
170
+ #elif defined(__x86_64__)
171
+ struct {
172
+ AbiMethod method;
173
+ } abi;
174
+ #elif defined(__arm__) || defined(__aarch64__) || defined(_M_ARM64)
175
+ struct {
176
+ bool regular;
177
+ int hfa32;
178
+ int offset;
179
+ } abi;
193
180
  #elif defined(__i386__) || defined(_M_IX86)
194
- bool trivial; // Only matters for return value
195
- int8_t fast;
181
+ bool trivial;
196
182
  #elif __riscv_xlen == 64 || defined(__loongarch64)
197
183
  bool use_memory;
198
184
  int8_t gpr_count;
@@ -203,35 +189,42 @@ struct ParameterInfo {
203
189
  };
204
190
 
205
191
  struct ValueCast {
206
- Napi::Reference<Napi::Value> ref;
192
+ napi_env env;
193
+ napi_ref ref;
207
194
  const TypeInfo *type;
195
+
196
+ ~ValueCast();
208
197
  };
209
198
 
210
199
  // Also used for callbacks, even though many members are not used in this case
211
200
  struct FunctionInfo {
212
201
  mutable std::atomic_int refcount { 1 };
213
202
 
203
+ napi_env env;
204
+ InstanceData *instance;
205
+ const LibraryHolder *lib = nullptr;
206
+
214
207
  const char *name;
215
208
  const char *decorated_name; // Only set for some platforms/calling conventions
216
209
  #if defined(_WIN32)
217
210
  int ordinal_name = -1;
218
211
  #endif
219
- const LibraryHolder *lib = nullptr;
220
212
 
221
213
  void *native;
222
214
  CallConvention convention;
223
215
 
224
- ParameterInfo ret;
216
+ ReturnInfo ret;
225
217
  HeapArray<ParameterInfo> parameters;
226
218
  int8_t required_parameters;
227
- int8_t out_parameters;
228
219
  bool variadic;
229
220
 
230
221
  // ABI-specific part
231
222
 
232
- Size args_size;
223
+ HeapArray<AbiInstruction> sync;
224
+ HeapArray<AbiInstruction> async;
225
+ Size stk_size;
233
226
  #if defined(__i386__) || defined(_M_IX86)
234
- bool fast;
227
+ int ret_pop;
235
228
  #else
236
229
  bool forward_fp;
237
230
  #endif
@@ -242,28 +235,36 @@ struct FunctionInfo {
242
235
  void Unref() const;
243
236
  };
244
237
 
238
+ template <typename T>
239
+ struct MemoryRange {
240
+ T *ptr;
241
+ T *end;
242
+ };
243
+
245
244
  struct InstanceMemory {
246
245
  ~InstanceMemory();
247
246
 
248
- Span<uint8_t> stack;
249
- Span<uint8_t> stack0;
250
- Span<uint8_t> heap;
247
+ MemoryRange<uint8_t> stack;
248
+ MemoryRange<uint8_t> stack0;
249
+ MemoryRange<uint8_t> heap;
250
+
251
+ // For big heap allocations
252
+ LinkedAllocator allocator;
251
253
 
252
254
  bool busy;
253
255
  bool temporary;
254
- int depth;
255
256
  };
256
257
 
257
258
  struct InstanceData {
258
259
  ~InstanceData();
259
260
 
261
+ napi_env env;
262
+
260
263
  BucketArray<TypeInfo> types;
261
264
  HashMap<const char *, const TypeInfo *> types_map;
262
265
  BucketArray<FunctionInfo> callbacks;
263
266
  Size base_types_count;
264
267
 
265
- bool debug;
266
-
267
268
  const TypeInfo *void_type;
268
269
  const TypeInfo *char_type;
269
270
  const TypeInfo *char16_type;
@@ -278,18 +279,23 @@ struct InstanceData {
278
279
  LocalArray<InstanceMemory *, 17> memories;
279
280
  int temporaries = 0;
280
281
 
282
+ // Variadic cache
283
+ FunctionInfo *variadic_func = nullptr;
284
+
285
+ napi_value (*translate_zero_call)(napi_env env, napi_callback_info info);
286
+
281
287
  std::thread::id main_thread_id;
282
288
  napi_threadsafe_function broker = nullptr;
283
289
 
290
+ CallData *sync_call = nullptr;
291
+
284
292
  #if defined(_WIN32)
285
293
  void *main_stack_max;
286
294
  void *main_stack_min;
287
-
288
- uint32_t last_error = 0;
289
295
  #endif
290
296
 
291
- BucketArray<BlockAllocator> encode_allocators;
292
- HashMap<void *, BlockAllocator *> encode_map;
297
+ BucketArray<LinkedAllocator> encode_allocators;
298
+ HashMap<void *, LinkedAllocator *> encode_map;
293
299
 
294
300
  HashMap<void *, int16_t> trampolines_map;
295
301
 
@@ -303,6 +309,9 @@ struct InstanceData {
303
309
  int resident_async_pools = DefaultResidentAsyncPools;
304
310
  int max_temporaries = DefaultMaxAsyncCalls - DefaultResidentAsyncPools;
305
311
  Size max_type_size = DefaultMaxTypeSize;
312
+
313
+ bool fast_pointers = true;
314
+ bool fast_callbacks = true;
306
315
  } config;
307
316
 
308
317
  struct {
@@ -314,13 +323,12 @@ static_assert(DefaultMaxAsyncCalls >= DefaultResidentAsyncPools);
314
323
  static_assert(MaxAsyncCalls >= DefaultMaxAsyncCalls);
315
324
 
316
325
  struct TrampolineInfo {
317
- InstanceData *instance;
326
+ int state;
318
327
 
328
+ InstanceData *instance;
319
329
  const FunctionInfo *proto;
320
330
  Napi::FunctionReference func;
321
331
  Napi::Reference<Napi::Value> recv;
322
-
323
- bool used;
324
332
  };
325
333
 
326
334
  struct SharedData {
@@ -342,12 +350,18 @@ static_assert(MaxTrampolines <= INT16_MAX);
342
350
 
343
351
  extern SharedData shared;
344
352
 
353
+ // Recent N-API functions are loaded dynamically
354
+ extern napi_status (NAPI_CDECL *node_api_create_property_key_utf8)(napi_env env, const char* str, size_t length, napi_value* result);
355
+ extern napi_status (NAPI_CDECL *node_api_post_finalizer)(node_api_basic_env env, napi_finalize finalize_cb, void* finalize_data, void* finalize_hint);
356
+ extern napi_value (*translate_zero_call)(napi_env env, napi_callback_info info);
357
+
345
358
  InstanceMemory *AllocateMemory(InstanceData *instance, Size stack_size, Size heap_size);
346
359
  void ReleaseMemory(InstanceData *instance, InstanceMemory *mem);
347
360
 
348
- Napi::Value TranslateNormalCall(const Napi::CallbackInfo &info);
349
- Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info);
350
- Napi::Value TranslateAsyncCall(const Napi::CallbackInfo &info);
361
+ napi_value TranslateFastCall(napi_env env, napi_callback_info info);
362
+ napi_value TranslateNormalCall(napi_env env, napi_callback_info info);
363
+ napi_value TranslateVariadicCall(napi_env env, napi_callback_info info);
364
+ napi_value TranslateAsyncCall(napi_env env, napi_callback_info info);
351
365
 
352
366
  bool InitAsyncBroker(Napi::Env env, InstanceData *instance);
353
367
 
@@ -60,10 +60,6 @@ bool PrototypeParser::Parse(const char *str, bool concrete, FunctionInfo *out_fu
60
60
  MarkError("Functions cannot have more than %1 parameters", MaxParameters);
61
61
  return false;
62
62
  }
63
- if ((param.directions & 2) && ++out_func->out_parameters >= MaxParameters) {
64
- MarkError("Functions cannot have more than out %1 parameters", MaxParameters);
65
- return false;
66
- }
67
63
 
68
64
  param.offset = (int8_t)out_func->parameters.len;
69
65
 
@@ -0,0 +1,39 @@
1
+ // SPDX-License-Identifier: GPL-3.0-or-later
2
+ // SPDX-FileCopyrightText: 2025 Niels Martignène <niels.martignene@protonmail.com>
3
+
4
+ #if !defined(PRIMITIVE)
5
+ #error Please define PRIMITIVE() before including primitives.inc
6
+ #endif
7
+
8
+ // Void is explictly not first so that it is not 0, for reasons related to N-API type tags.
9
+ // Look at TypeInfo definition for more information!
10
+
11
+ PRIMITIVE(Bool)
12
+ PRIMITIVE(Void)
13
+ PRIMITIVE(Int8)
14
+ PRIMITIVE(UInt8)
15
+ PRIMITIVE(Int16)
16
+ PRIMITIVE(Int16S) // Keep behind Int16
17
+ PRIMITIVE(UInt16)
18
+ PRIMITIVE(UInt16S) // Keep behind UInt16
19
+ PRIMITIVE(Int32)
20
+ PRIMITIVE(Int32S) // Keep behind Int32
21
+ PRIMITIVE(UInt32)
22
+ PRIMITIVE(UInt32S) // Keep behind UInt32
23
+ PRIMITIVE(Int64)
24
+ PRIMITIVE(Int64S) // Keep behind Int64
25
+ PRIMITIVE(UInt64)
26
+ PRIMITIVE(UInt64S) // Keep behind UInt64
27
+ PRIMITIVE(String)
28
+ PRIMITIVE(String16)
29
+ PRIMITIVE(String32)
30
+ PRIMITIVE(Pointer)
31
+ PRIMITIVE(Record)
32
+ PRIMITIVE(Union)
33
+ PRIMITIVE(Array)
34
+ PRIMITIVE(Float32)
35
+ PRIMITIVE(Float64)
36
+ PRIMITIVE(Callback)
37
+ PRIMITIVE(Prototype)
38
+
39
+ #undef PRIMITIVE
@@ -20,7 +20,7 @@ function run() {
20
20
  let args = process.argv.slice(2);
21
21
 
22
22
  if (args.length < 2)
23
- throw new Error('Usage: write_trampolines.js DIRECTORY N');
23
+ throw new Error('Usage: trampolines.js DIRECTORY N');
24
24
 
25
25
  let dest_dir = args[0]?.trim?.();
26
26
  let n = parseInt(args[1], 10);