koffi 2.14.1 → 2.15.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 (102) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/build/koffi/darwin_arm64/koffi.node +0 -0
  3. package/build/koffi/darwin_x64/koffi.node +0 -0
  4. package/build/koffi/freebsd_arm64/koffi.node +0 -0
  5. package/build/koffi/freebsd_ia32/koffi.node +0 -0
  6. package/build/koffi/freebsd_x64/koffi.node +0 -0
  7. package/build/koffi/linux_arm64/koffi.node +0 -0
  8. package/build/koffi/linux_armhf/koffi.node +0 -0
  9. package/build/koffi/linux_ia32/koffi.node +0 -0
  10. package/build/koffi/linux_loong64/koffi.node +0 -0
  11. package/build/koffi/linux_riscv64d/koffi.node +0 -0
  12. package/build/koffi/linux_x64/koffi.node +0 -0
  13. package/build/koffi/musl_arm64/koffi.node +0 -0
  14. package/build/koffi/musl_x64/koffi.node +0 -0
  15. package/build/koffi/openbsd_ia32/koffi.node +0 -0
  16. package/build/koffi/openbsd_x64/koffi.node +0 -0
  17. package/build/koffi/win32_arm64/koffi.node +0 -0
  18. package/build/koffi/win32_ia32/koffi.node +0 -0
  19. package/build/koffi/win32_x64/koffi.node +0 -0
  20. package/doc/assets.ini +2 -1
  21. package/doc/build.sh +9 -0
  22. package/doc/pages/404.md +17 -0
  23. package/doc/pages/index.md +1 -1
  24. package/doc/pages/misc.md +16 -11
  25. package/doc/pages.ini +4 -0
  26. package/doc/static/highlight.js +2 -14
  27. package/doc/static/koffi.css +3 -15
  28. package/doc/static/print.css +2 -14
  29. package/index.d.ts +29 -24
  30. package/index.js +8 -8
  31. package/indirect.js +8 -8
  32. package/{src/core → lib/native}/base/base.cc +1058 -630
  33. package/{src/core → lib/native}/base/base.hh +334 -165
  34. package/{src/core → lib/native}/base/crc.inc +2 -20
  35. package/lib/native/base/crc_gen.py +72 -0
  36. package/{src/core → lib/native}/base/mimetypes.inc +2 -20
  37. package/{src/core → lib/native}/base/mimetypes_gen.py +2 -21
  38. package/lib/native/base/tower.cc +821 -0
  39. package/lib/native/base/tower.hh +81 -0
  40. package/{src/core → lib/native}/base/unicode.inc +2 -20
  41. package/{src/core → lib/native}/base/unicode_gen.py +4 -41
  42. package/package.json +1 -1
  43. package/src/cnoke/assets/FindCNoke.cmake +8 -20
  44. package/src/cnoke/assets/win_delay_hook.c +2 -20
  45. package/src/cnoke/cnoke.js +2 -21
  46. package/src/cnoke/src/builder.js +2 -20
  47. package/src/cnoke/src/index.js +2 -20
  48. package/src/cnoke/src/tools.js +2 -20
  49. package/src/koffi/CMakeLists.txt +19 -22
  50. package/src/koffi/cmake/raylib.cmake +5 -22
  51. package/src/koffi/cmake/sqlite3.cmake +2 -20
  52. package/src/koffi/src/abi_arm32.cc +7 -25
  53. package/src/koffi/src/abi_arm32_asm.S +2 -20
  54. package/src/koffi/src/abi_arm64.cc +7 -25
  55. package/src/koffi/src/abi_arm64_asm.S +2 -20
  56. package/src/koffi/src/abi_arm64_asm.asm +2 -20
  57. package/src/koffi/src/abi_loong64.cc +2 -20
  58. package/src/koffi/src/abi_loong64_asm.S +2 -20
  59. package/src/koffi/src/abi_riscv64.cc +7 -25
  60. package/src/koffi/src/abi_riscv64_asm.S +2 -20
  61. package/src/koffi/src/abi_x64_sysv.cc +7 -25
  62. package/src/koffi/src/abi_x64_sysv_asm.S +2 -20
  63. package/src/koffi/src/abi_x64_win.cc +12 -30
  64. package/src/koffi/src/abi_x64_win_asm.asm +2 -20
  65. package/src/koffi/src/abi_x86.cc +7 -25
  66. package/src/koffi/src/abi_x86_asm.S +2 -20
  67. package/src/koffi/src/abi_x86_asm.asm +2 -20
  68. package/src/koffi/src/call.cc +25 -45
  69. package/src/koffi/src/call.hh +3 -21
  70. package/src/koffi/src/errno.inc +2 -20
  71. package/src/koffi/src/ffi.cc +62 -62
  72. package/src/koffi/src/ffi.hh +14 -29
  73. package/src/koffi/src/init.js +2 -20
  74. package/src/koffi/src/parser.cc +13 -27
  75. package/src/koffi/src/parser.hh +3 -21
  76. package/src/koffi/src/trampolines/armasm.inc +0 -21
  77. package/src/koffi/src/trampolines/gnu.inc +0 -21
  78. package/src/koffi/src/trampolines/masm32.inc +0 -21
  79. package/src/koffi/src/trampolines/masm64.inc +0 -21
  80. package/src/koffi/src/trampolines/prototypes.inc +0 -21
  81. package/src/koffi/src/util.cc +44 -59
  82. package/src/koffi/src/util.hh +6 -24
  83. package/src/koffi/src/uv.cc +193 -0
  84. package/src/koffi/src/uv.def +10 -0
  85. package/src/koffi/src/uv.hh +40 -0
  86. package/src/koffi/src/win32.cc +2 -20
  87. package/src/koffi/src/win32.hh +3 -21
  88. package/vendor/node-api-headers/include/uv/aix.h +32 -0
  89. package/vendor/node-api-headers/include/uv/bsd.h +34 -0
  90. package/vendor/node-api-headers/include/uv/darwin.h +61 -0
  91. package/vendor/node-api-headers/include/uv/errno.h +483 -0
  92. package/vendor/node-api-headers/include/uv/linux.h +34 -0
  93. package/vendor/node-api-headers/include/uv/os390.h +33 -0
  94. package/vendor/node-api-headers/include/uv/posix.h +31 -0
  95. package/vendor/node-api-headers/include/uv/sunos.h +44 -0
  96. package/vendor/node-api-headers/include/uv/threadpool.h +37 -0
  97. package/vendor/node-api-headers/include/uv/tree.h +521 -0
  98. package/vendor/node-api-headers/include/uv/unix.h +512 -0
  99. package/vendor/node-api-headers/include/uv/version.h +43 -0
  100. package/vendor/node-api-headers/include/uv/win.h +698 -0
  101. package/vendor/node-api-headers/include/uv.h +1990 -0
  102. package/src/core/base/crc_gen.py +0 -109
@@ -1,25 +1,7 @@
1
- // Copyright (C) 2025 Niels Martignène <niels.martignene@protonmail.com>
2
- //
3
- // Permission is hereby granted, free of charge, to any person obtaining a copy of
4
- // this software and associated documentation files (the “Software”), to deal in
5
- // the Software without restriction, including without limitation the rights to use,
6
- // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
7
- // Software, and to permit persons to whom the Software is furnished to do so,
8
- // subject to the following conditions:
9
- //
10
- // The above copyright notice and this permission notice shall be included in all
11
- // copies or substantial portions of the Software.
12
- //
13
- // THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
14
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
15
- // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17
- // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18
- // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20
- // OTHER DEALINGS IN THE SOFTWARE.
21
-
22
- #include "src/core/base/base.hh"
1
+ // SPDX-License-Identifier: MIT
2
+ // SPDX-FileCopyrightText: 2025 Niels Martignène <niels.martignene@protonmail.com>
3
+
4
+ #include "lib/native/base/base.hh"
23
5
  #include "call.hh"
24
6
  #include "ffi.hh"
25
7
  #include "util.hh"
@@ -88,15 +70,7 @@ void CallData::Dispose()
88
70
  }
89
71
  }
90
72
 
91
- instance->temporaries -= mem->temporary;
92
-
93
- if (!--mem->depth) {
94
- mem->busy = false;
95
-
96
- if (mem->temporary) {
97
- delete mem;
98
- }
99
- }
73
+ ReleaseMemory(instance, mem);
100
74
 
101
75
  instance = nullptr;
102
76
  }
@@ -264,6 +238,8 @@ Size CallData::PushString16Value(Napi::Value value, const char16_t **out_str16)
264
238
 
265
239
  Size CallData::PushString32Value(Napi::Value value, const char32_t **out_str32)
266
240
  {
241
+ static const char32_t ReplacementChar = 0x0000FFFD;
242
+
267
243
  Span<char32_t> buf;
268
244
 
269
245
  Span<const char16_t> buf16;
@@ -287,15 +263,19 @@ Size CallData::PushString32Value(Napi::Value value, const char32_t **out_str32)
287
263
  char32_t uc = buf16[i];
288
264
 
289
265
  if (uc >= 0xD800 && uc <= 0xDBFF) {
290
- char16_t uc2 = buf16.ptr[++i];
266
+ if (++i < buf16.len) {
267
+ char16_t uc2 = buf16.ptr[i];
291
268
 
292
- if (uc2 >= 0xDC00 && uc2 <= 0xDFFF) {
293
- uc = ((uc - 0xD800) << 10) + (uc2 - 0xDC00) + 0x10000u;
269
+ if (uc2 >= 0xDC00 && uc2 <= 0xDFFF) [[likely]] {
270
+ uc = ((uc - 0xD800) << 10) + (uc2 - 0xDC00) + 0x10000u;
271
+ } else {
272
+ uc = ReplacementChar;
273
+ }
294
274
  } else {
295
- uc = '?';
275
+ uc = ReplacementChar;
296
276
  }
297
- } else if (uc >= 0xDC00 && uc <= 0xDFFF) {
298
- uc = '?';
277
+ } else if (uc >= 0xDC00 && uc <= 0xDFFF) [[unlikely]] {
278
+ uc = ReplacementChar;
299
279
  }
300
280
 
301
281
  buf[j++] = uc;
@@ -316,7 +296,7 @@ bool CallData::PushObject(Napi::Object obj, const TypeInfo *type, uint8_t *origi
316
296
  if (type->primitive == PrimitiveKind::Record) {
317
297
  members = type->members;
318
298
  } else if (type->primitive == PrimitiveKind::Union) {
319
- if (CheckValueTag(instance, obj, &MagicUnionMarker)) {
299
+ if (CheckValueTag(obj, &MagicUnionMarker)) {
320
300
  MagicUnion *u = MagicUnion::Unwrap(obj);
321
301
  const uint8_t *raw = u->GetRaw();
322
302
 
@@ -909,7 +889,7 @@ bool CallData::PushStringArray(Napi::Value obj, const TypeInfo *type, uint8_t *o
909
889
 
910
890
  bool CallData::PushPointer(Napi::Value value, const TypeInfo *type, int directions, void **out_ptr)
911
891
  {
912
- if (CheckValueTag(instance, value, &CastMarker)) {
892
+ if (CheckValueTag(value, &CastMarker)) {
913
893
  Napi::External<ValueCast> external = value.As<Napi::External<ValueCast>>();
914
894
  ValueCast *cast = external.Data();
915
895
 
@@ -932,8 +912,8 @@ bool CallData::PushPointer(Napi::Value value, const TypeInfo *type, int directio
932
912
  type->primitive == PrimitiveKind::String16 ||
933
913
  type->primitive == PrimitiveKind::String32);
934
914
 
935
- if (!CheckValueTag(instance, value, type->ref.marker) &&
936
- !CheckValueTag(instance, value, instance->void_type) &&
915
+ if (!CheckValueTag(value, type->ref.marker) &&
916
+ !CheckValueTag(value, instance->void_type) &&
937
917
  ref != instance->void_type) [[unlikely]]
938
918
  goto unexpected;
939
919
 
@@ -1000,7 +980,7 @@ bool CallData::PushPointer(Napi::Value value, const TypeInfo *type, int directio
1000
980
  ptr = AllocHeap(ref->size, 16);
1001
981
 
1002
982
  if (ref->primitive == PrimitiveKind::Union &&
1003
- (directions & 2) && !CheckValueTag(instance, obj, &MagicUnionMarker)) [[unlikely]] {
983
+ (directions & 2) && !CheckValueTag(obj, &MagicUnionMarker)) [[unlikely]] {
1004
984
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected union value", GetValueType(instance, obj));
1005
985
  return false;
1006
986
  }
@@ -1108,9 +1088,9 @@ bool CallData::PushCallback(Napi::Value value, const TypeInfo *type, void **out_
1108
1088
  return false;
1109
1089
 
1110
1090
  *out_ptr = ptr;
1111
- } else if (CheckValueTag(instance, value, type->ref.marker)) {
1091
+ } else if (CheckValueTag(value, type->ref.marker)) {
1112
1092
  *out_ptr = value.As<Napi::External<void>>().Data();
1113
- } else if (CheckValueTag(instance, value, &CastMarker)) {
1093
+ } else if (CheckValueTag(value, &CastMarker)) {
1114
1094
  Napi::External<ValueCast> external = value.As<Napi::External<ValueCast>>();
1115
1095
  ValueCast *cast = external.Data();
1116
1096
 
@@ -1324,7 +1304,7 @@ void CallData::PopOutArguments()
1324
1304
  case OutArgument::Kind::Object: {
1325
1305
  Napi::Object obj = value.As<Napi::Object>();
1326
1306
 
1327
- if (CheckValueTag(instance, value, &MagicUnionMarker)) {
1307
+ if (CheckValueTag(value, &MagicUnionMarker)) {
1328
1308
  MagicUnion *u = MagicUnion::Unwrap(obj);
1329
1309
  u->SetRaw(out.ptr);
1330
1310
  } else {
@@ -1,27 +1,9 @@
1
- // Copyright (C) 2025 Niels Martignène <niels.martignene@protonmail.com>
2
- //
3
- // Permission is hereby granted, free of charge, to any person obtaining a copy of
4
- // this software and associated documentation files (the “Software”), to deal in
5
- // the Software without restriction, including without limitation the rights to use,
6
- // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
7
- // Software, and to permit persons to whom the Software is furnished to do so,
8
- // subject to the following conditions:
9
- //
10
- // The above copyright notice and this permission notice shall be included in all
11
- // copies or substantial portions of the Software.
12
- //
13
- // THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
14
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
15
- // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17
- // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18
- // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20
- // OTHER DEALINGS IN THE SOFTWARE.
1
+ // SPDX-License-Identifier: MIT
2
+ // SPDX-FileCopyrightText: 2025 Niels Martignène <niels.martignene@protonmail.com>
21
3
 
22
4
  #pragma once
23
5
 
24
- #include "src/core/base/base.hh"
6
+ #include "lib/native/base/base.hh"
25
7
  #include "ffi.hh"
26
8
  #include "util.hh"
27
9
 
@@ -1,23 +1,5 @@
1
- // Copyright (C) 2025 Niels Martignène <niels.martignene@protonmail.com>
2
- //
3
- // Permission is hereby granted, free of charge, to any person obtaining a copy of
4
- // this software and associated documentation files (the “Software”), to deal in
5
- // the Software without restriction, including without limitation the rights to use,
6
- // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
7
- // Software, and to permit persons to whom the Software is furnished to do so,
8
- // subject to the following conditions:
9
- //
10
- // The above copyright notice and this permission notice shall be included in all
11
- // copies or substantial portions of the Software.
12
- //
13
- // THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
14
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
15
- // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17
- // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18
- // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20
- // OTHER DEALINGS IN THE SOFTWARE.
1
+ // SPDX-License-Identifier: MIT
2
+ // SPDX-FileCopyrightText: 2025 Niels Martignène <niels.martignene@protonmail.com>
21
3
 
22
4
  #include <errno.h>
23
5
 
@@ -1,29 +1,12 @@
1
- // Copyright (C) 2025 Niels Martignène <niels.martignene@protonmail.com>
2
- //
3
- // Permission is hereby granted, free of charge, to any person obtaining a copy of
4
- // this software and associated documentation files (the “Software”), to deal in
5
- // the Software without restriction, including without limitation the rights to use,
6
- // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
7
- // Software, and to permit persons to whom the Software is furnished to do so,
8
- // subject to the following conditions:
9
- //
10
- // The above copyright notice and this permission notice shall be included in all
11
- // copies or substantial portions of the Software.
12
- //
13
- // THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
14
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
15
- // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17
- // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18
- // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20
- // OTHER DEALINGS IN THE SOFTWARE.
21
-
22
- #include "src/core/base/base.hh"
1
+ // SPDX-License-Identifier: MIT
2
+ // SPDX-FileCopyrightText: 2025 Niels Martignène <niels.martignene@protonmail.com>
3
+
4
+ #include "lib/native/base/base.hh"
23
5
  #include "ffi.hh"
24
6
  #include "call.hh"
25
7
  #include "parser.hh"
26
8
  #include "util.hh"
9
+ #include "uv.hh"
27
10
  #if defined(_WIN32)
28
11
  #include "win32.hh"
29
12
  #endif
@@ -222,7 +205,7 @@ static bool MapType(Napi::Env env, InstanceData *instance, const TypeInfo *type,
222
205
  }
223
206
 
224
207
  bool inserted;
225
- instance->types_map.TrySet(name, type, &inserted);
208
+ instance->types_map.InsertOrGet(name, type, &inserted);
226
209
 
227
210
  if (!inserted) {
228
211
  ThrowError<Napi::Error>(env, "Duplicate type name '%1'", name);
@@ -244,7 +227,7 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
244
227
 
245
228
  bool skip = (info.Length() > 1);
246
229
  bool named = skip && !IsNullOrUndefined(info[0]);
247
- bool redefine = named && CheckValueTag(instance, info[0], &TypeInfoMarker);
230
+ bool redefine = named && CheckValueTag(info[0], &TypeInfoMarker);
248
231
 
249
232
  if (named && !info[0].IsString() && !redefine) {
250
233
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
@@ -364,7 +347,7 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
364
347
  }
365
348
 
366
349
  bool inserted;
367
- members.TrySet(member.name, &inserted);
350
+ members.InsertOrGet(member.name, &inserted);
368
351
 
369
352
  if (!inserted) {
370
353
  ThrowError<Napi::Error>(env, "Duplicate member '%1' in struct '%2'", member.name, type->name);
@@ -414,7 +397,7 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
414
397
  type = replace;
415
398
  }
416
399
 
417
- return WrapType(env, instance, type);
400
+ return WrapType(env, type);
418
401
  }
419
402
 
420
403
  static Napi::Value CreatePaddedStructType(const Napi::CallbackInfo &info)
@@ -439,7 +422,7 @@ static Napi::Value CreateUnionType(const Napi::CallbackInfo &info)
439
422
 
440
423
  bool skip = (info.Length() > 1);
441
424
  bool named = skip && !IsNullOrUndefined(info[0]);
442
- bool redefine = named && CheckValueTag(instance, info[0], &TypeInfoMarker);
425
+ bool redefine = named && CheckValueTag(info[0], &TypeInfoMarker);
443
426
 
444
427
  if (named && !info[0].IsString() && !redefine) {
445
428
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
@@ -554,7 +537,7 @@ static Napi::Value CreateUnionType(const Napi::CallbackInfo &info)
554
537
  }
555
538
 
556
539
  bool inserted;
557
- members.TrySet(member.name, &inserted);
540
+ members.InsertOrGet(member.name, &inserted);
558
541
 
559
542
  if (!inserted) {
560
543
  ThrowError<Napi::Error>(env, "Duplicate member '%1' in union '%2'", member.name, type->name);
@@ -583,13 +566,12 @@ static Napi::Value CreateUnionType(const Napi::CallbackInfo &info)
583
566
  type = replace;
584
567
  }
585
568
 
586
- return WrapType(env, instance, type);
569
+ return WrapType(env, type);
587
570
  }
588
571
 
589
572
  Napi::Value InstantiateUnion(const Napi::CallbackInfo &info)
590
573
  {
591
574
  Napi::Env env = info.Env();
592
- InstanceData *instance = env.GetInstanceData<InstanceData>();
593
575
 
594
576
  if (!info.IsConstructCall()) {
595
577
  ThrowError<Napi::TypeError>(env, "This function is a constructor and must be called with new");
@@ -609,7 +591,7 @@ Napi::Value InstantiateUnion(const Napi::CallbackInfo &info)
609
591
  }
610
592
 
611
593
  Napi::Object wrapper = type->construct.New({}).As<Napi::Object>();
612
- SetValueTag(instance, wrapper, &MagicUnionMarker);
594
+ SetValueTag(wrapper, &MagicUnionMarker);
613
595
 
614
596
  return wrapper;
615
597
  }
@@ -626,7 +608,7 @@ static Napi::Value CreateOpaqueType(const Napi::CallbackInfo &info)
626
608
  return env.Null();
627
609
  }
628
610
 
629
- Napi::String name = info[0].As<Napi::String>();
611
+ Napi::String name = info[0].As<Napi::String>();
630
612
 
631
613
  TypeInfo *type = instance->types.AppendDefault();
632
614
  K_DEFER_N(err_guard) { instance->types.RemoveLast(1); };
@@ -643,7 +625,7 @@ static Napi::Value CreateOpaqueType(const Napi::CallbackInfo &info)
643
625
  return env.Null();
644
626
  err_guard.Disable();
645
627
 
646
- return WrapType(env, instance, type);
628
+ return WrapType(env, type);
647
629
  }
648
630
 
649
631
  static Napi::Value CreatePointerType(const Napi::CallbackInfo &info)
@@ -712,7 +694,7 @@ static Napi::Value CreatePointerType(const Napi::CallbackInfo &info)
712
694
  type = copy;
713
695
  }
714
696
 
715
- return WrapType(env, instance, type);
697
+ return WrapType(env, type);
716
698
  }
717
699
 
718
700
  static Napi::Value EncodePointerDirection(const Napi::CallbackInfo &info, int directions)
@@ -720,7 +702,6 @@ static Napi::Value EncodePointerDirection(const Napi::CallbackInfo &info, int di
720
702
  K_ASSERT(directions >= 1 && directions <= 3);
721
703
 
722
704
  Napi::Env env = info.Env();
723
- InstanceData *instance = env.GetInstanceData<InstanceData>();
724
705
 
725
706
  if (info.Length() < 1) {
726
707
  ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
@@ -742,7 +723,7 @@ static Napi::Value EncodePointerDirection(const Napi::CallbackInfo &info, int di
742
723
  // Embed direction in unused pointer bits
743
724
  const TypeInfo *marked = (const TypeInfo *)((uint8_t *)type + directions - 1);
744
725
 
745
- return WrapType(env, instance, marked);
726
+ return WrapType(env, marked);
746
727
  }
747
728
 
748
729
  static Napi::Value MarkIn(const Napi::CallbackInfo &info)
@@ -810,7 +791,7 @@ static Napi::Value CreateDisposableType(const Napi::CallbackInfo &info)
810
791
  const Napi::FunctionReference &ref = type->dispose_ref;
811
792
 
812
793
  Napi::External<void> external = Napi::External<void>::New(env, (void *)ptr);
813
- SetValueTag(instance, external, type->ref.marker);
794
+ SetValueTag(external, type->ref.marker);
814
795
 
815
796
  Napi::Value self = env.Null();
816
797
  napi_value args[] = {
@@ -845,7 +826,7 @@ static Napi::Value CreateDisposableType(const Napi::CallbackInfo &info)
845
826
  // If the insert succeeds, we cannot fail anymore
846
827
  if (named) {
847
828
  bool inserted;
848
- instance->types_map.TrySet(type->name, type, &inserted);
829
+ instance->types_map.InsertOrGet(type->name, type, &inserted);
849
830
 
850
831
  if (!inserted) {
851
832
  ThrowError<Napi::Error>(env, "Duplicate type name '%1'", type->name);
@@ -854,7 +835,7 @@ static Napi::Value CreateDisposableType(const Napi::CallbackInfo &info)
854
835
  }
855
836
  err_guard.Disable();
856
837
 
857
- return WrapType(env, instance, type);
838
+ return WrapType(env, type);
858
839
  }
859
840
 
860
841
  static inline bool GetExternalPointer(Napi::Env env, Napi::Value value, void **out_ptr)
@@ -864,9 +845,9 @@ static inline bool GetExternalPointer(Napi::Env env, Napi::Value value, void **o
864
845
  if (IsNullOrUndefined(value)) {
865
846
  *out_ptr = 0;
866
847
  return true;
867
- } else if (value.IsExternal() && !CheckValueTag(instance, value, &TypeInfoMarker) &&
868
- !CheckValueTag(instance, value, &CastMarker) &&
869
- !CheckValueTag(instance, value, &MagicUnionMarker)) {
848
+ } else if (value.IsExternal() && !CheckValueTag(value, &TypeInfoMarker) &&
849
+ !CheckValueTag(value, &CastMarker) &&
850
+ !CheckValueTag(value, &MagicUnionMarker)) {
870
851
  Napi::External<void> external = value.As<Napi::External<void>>();
871
852
  void *ptr = external.Data();
872
853
 
@@ -922,7 +903,7 @@ static Napi::Value CallAlloc(const Napi::CallbackInfo &info)
922
903
  }
923
904
 
924
905
  Napi::External<void> external = Napi::External<void>::New(env, ptr);
925
- SetValueTag(instance, external, type);
906
+ SetValueTag(external, type);
926
907
 
927
908
  return external;
928
909
  }
@@ -1047,7 +1028,7 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
1047
1028
  type->countedby = DuplicateString(str.Utf8Value().c_str(), &instance->str_alloc).ptr;
1048
1029
  }
1049
1030
 
1050
- return WrapType(env, instance, type);
1031
+ return WrapType(env, type);
1051
1032
  }
1052
1033
 
1053
1034
  static bool ParseClassicFunction(const Napi::CallbackInfo &info, bool concrete, FunctionInfo *out_func)
@@ -1210,7 +1191,7 @@ static Napi::Value CreateFunctionType(const Napi::CallbackInfo &info)
1210
1191
 
1211
1192
  instance->types_map.Set(type->name, type);
1212
1193
 
1213
- return WrapType(env, instance, type);
1194
+ return WrapType(env, type);
1214
1195
  }
1215
1196
 
1216
1197
  static Napi::Value CreateTypeAlias(const Napi::CallbackInfo &info)
@@ -1238,7 +1219,7 @@ static Napi::Value CreateTypeAlias(const Napi::CallbackInfo &info)
1238
1219
  if (!MapType(env, instance, type, alias))
1239
1220
  return env.Null();
1240
1221
 
1241
- return WrapType(env, instance, type);
1222
+ return WrapType(env, type);
1242
1223
  }
1243
1224
 
1244
1225
  static Napi::Value GetTypeSize(const Napi::CallbackInfo &info)
@@ -1310,7 +1291,6 @@ static Napi::Value GetMemberOffset(const Napi::CallbackInfo &info)
1310
1291
  static Napi::Value GetResolvedType(const Napi::CallbackInfo &info)
1311
1292
  {
1312
1293
  Napi::Env env = info.Env();
1313
- InstanceData *instance = env.GetInstanceData<InstanceData>();
1314
1294
 
1315
1295
  if (info.Length() < 1) {
1316
1296
  ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
@@ -1321,13 +1301,12 @@ static Napi::Value GetResolvedType(const Napi::CallbackInfo &info)
1321
1301
  if (!type)
1322
1302
  return env.Null();
1323
1303
 
1324
- return WrapType(env, instance, type);
1304
+ return WrapType(env, type);
1325
1305
  }
1326
1306
 
1327
1307
  static Napi::Value GetTypeDefinition(const Napi::CallbackInfo &info)
1328
1308
  {
1329
1309
  Napi::Env env = info.Env();
1330
- InstanceData *instance = env.GetInstanceData<InstanceData>();
1331
1310
 
1332
1311
  if (info.Length() < 1) {
1333
1312
  ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
@@ -1378,7 +1357,7 @@ static Napi::Value GetTypeDefinition(const Napi::CallbackInfo &info)
1378
1357
  defn.Set("hint", ArrayHintNames[(int)type->hint]);
1379
1358
  } [[fallthrough]];
1380
1359
  case PrimitiveKind::Pointer: {
1381
- Napi::Value value = WrapType(env, instance, type->ref.type);
1360
+ Napi::Value value = WrapType(env, type->ref.type);
1382
1361
  defn.Set("ref", value);
1383
1362
  } break;
1384
1363
  case PrimitiveKind::Record:
@@ -1389,7 +1368,7 @@ static Napi::Value GetTypeDefinition(const Napi::CallbackInfo &info)
1389
1368
  Napi::Object obj = Napi::Object::New(env);
1390
1369
 
1391
1370
  obj.Set("name", member.name);
1392
- obj.Set("type", WrapType(env, instance, member.type));
1371
+ obj.Set("type", WrapType(env, member.type));
1393
1372
  obj.Set("offset", member.offset);
1394
1373
  if (member.countedby >= 0) {
1395
1374
  obj.Set("countedBy", type->members[member.countedby].name);
@@ -1409,9 +1388,9 @@ static Napi::Value GetTypeDefinition(const Napi::CallbackInfo &info)
1409
1388
  return type->defn.Value();
1410
1389
  }
1411
1390
 
1412
- static InstanceMemory *AllocateMemory(InstanceData *instance, Size stack_size, Size heap_size)
1391
+ InstanceMemory *AllocateMemory(InstanceData *instance, Size stack_size, Size heap_size)
1413
1392
  {
1414
- std::lock_guard<std::mutex> lock(instance->memories_mutex);
1393
+ std::lock_guard<std::mutex> lock(instance->mem_mutex);
1415
1394
 
1416
1395
  for (Size i = 1; i < instance->memories.len; i++) {
1417
1396
  InstanceMemory *mem = instance->memories[i];
@@ -1424,7 +1403,7 @@ static InstanceMemory *AllocateMemory(InstanceData *instance, Size stack_size, S
1424
1403
 
1425
1404
  bool temporary = (instance->memories.len > instance->config.resident_async_pools);
1426
1405
 
1427
- if (temporary && instance->temporaries >= instance->config.max_temporaries) [[unlikely]]
1406
+ if (temporary && instance->temporaries > instance->config.max_temporaries)
1428
1407
  return nullptr;
1429
1408
 
1430
1409
  InstanceMemory *mem = new InstanceMemory();
@@ -1475,6 +1454,25 @@ static InstanceMemory *AllocateMemory(InstanceData *instance, Size stack_size, S
1475
1454
  return mem;
1476
1455
  }
1477
1456
 
1457
+ void ReleaseMemory(InstanceData *instance, InstanceMemory *mem)
1458
+ {
1459
+ if (--mem->depth)
1460
+ return;
1461
+
1462
+ // The first InstanceMemory is used for sync calls, no need to manage the async stuff
1463
+ if (mem == instance->memories[0])
1464
+ return;
1465
+
1466
+ std::lock_guard<std::mutex> lock(instance->mem_mutex);
1467
+
1468
+ if (mem->temporary) {
1469
+ instance->temporaries--;
1470
+ delete mem;
1471
+ } else {
1472
+ mem->busy = false;
1473
+ }
1474
+ }
1475
+
1478
1476
  static Napi::Value TranslateNormalCall(const FunctionInfo *func, void *native,
1479
1477
  const Napi::CallbackInfo &info)
1480
1478
  {
@@ -1825,7 +1823,7 @@ static Napi::Value FindSymbol(const Napi::CallbackInfo &info)
1825
1823
  }
1826
1824
 
1827
1825
  Napi::External<void> external = Napi::External<void>::New(env, ptr);
1828
- SetValueTag(instance, external, &type);
1826
+ SetValueTag(external, &type);
1829
1827
 
1830
1828
  return external;
1831
1829
  }
@@ -1876,7 +1874,7 @@ static Napi::Value LoadSharedLibrary(const Napi::CallbackInfo &info)
1876
1874
 
1877
1875
  if (!instance->memories.len) {
1878
1876
  AllocateMemory(instance, instance->config.sync_stack_size, instance->config.sync_heap_size);
1879
- K_ASSERT(instance->memories.len);
1877
+ K_ASSERT(instance->memories.len == 1);
1880
1878
  }
1881
1879
 
1882
1880
  // Load shared library
@@ -1997,7 +1995,7 @@ static Napi::Value RegisterCallback(const Napi::CallbackInfo &info)
1997
1995
  void *ptr = GetTrampoline(idx, type->ref.proto);
1998
1996
 
1999
1997
  Napi::External<void> external = Napi::External<void>::New(env, ptr);
2000
- SetValueTag(instance, external, type->ref.marker);
1998
+ SetValueTag(external, type->ref.marker);
2001
1999
 
2002
2000
  // Cache index for fast unregistration
2003
2001
  instance->trampolines_map.Set(ptr, idx);
@@ -2054,7 +2052,6 @@ static Napi::Value UnregisterCallback(const Napi::CallbackInfo &info)
2054
2052
  static Napi::Value CastValue(const Napi::CallbackInfo &info)
2055
2053
  {
2056
2054
  Napi::Env env = info.Env();
2057
- InstanceData *instance = env.GetInstanceData<InstanceData>();
2058
2055
 
2059
2056
  if (info.Length() < 2) [[unlikely]] {
2060
2057
  ThrowError<Napi::TypeError>(env, "Expected 2 arguments, got %1", info.Length());
@@ -2081,7 +2078,7 @@ static Napi::Value CastValue(const Napi::CallbackInfo &info)
2081
2078
  cast->type = type;
2082
2079
 
2083
2080
  Napi::External<ValueCast> external = Napi::External<ValueCast>::New(env, cast, [](Napi::Env, ValueCast *cast) { delete cast; });
2084
- SetValueTag(instance, external, &CastMarker);
2081
+ SetValueTag(external, &CastMarker);
2085
2082
 
2086
2083
  return external;
2087
2084
  }
@@ -2384,11 +2381,11 @@ static void RegisterPrimitiveType(Napi::Env env, Napi::Object map, std::initiali
2384
2381
  type->ref.marker = marker;
2385
2382
  }
2386
2383
 
2387
- Napi::Value wrapper = WrapType(env, instance, type);
2384
+ Napi::Value wrapper = WrapType(env, type);
2388
2385
 
2389
2386
  for (const char *name: names) {
2390
2387
  bool inserted;
2391
- instance->types_map.TrySet(name, type, &inserted);
2388
+ instance->types_map.InsertOrGet(name, type, &inserted);
2392
2389
  K_ASSERT(inserted);
2393
2390
 
2394
2391
  if (!EndsWith(name, "*")) {
@@ -2596,9 +2593,12 @@ static Napi::Object InitModule(Napi::Env env, Napi::Object exports)
2596
2593
  exports.Set("node", node);
2597
2594
 
2598
2595
  Napi::External<void> external = Napi::External<void>::New(env, (napi_env)env);
2599
- SetValueTag(instance, external, instance->void_type);
2596
+ SetValueTag(external, instance->void_type);
2600
2597
 
2601
2598
  node.Set("env", external);
2599
+
2600
+ node.Set("poll", Napi::Function::New(env, &Poll, "poll"));
2601
+ node.Set("PollHandle", PollHandle::Define(env));
2602
2602
  }
2603
2603
 
2604
2604
  exports.Set("version", Napi::String::New(env, K_STRINGIFY(VERSION)));
@@ -1,27 +1,9 @@
1
- // Copyright (C) 2025 Niels Martignène <niels.martignene@protonmail.com>
2
- //
3
- // Permission is hereby granted, free of charge, to any person obtaining a copy of
4
- // this software and associated documentation files (the “Software”), to deal in
5
- // the Software without restriction, including without limitation the rights to use,
6
- // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
7
- // Software, and to permit persons to whom the Software is furnished to do so,
8
- // subject to the following conditions:
9
- //
10
- // The above copyright notice and this permission notice shall be included in all
11
- // copies or substantial portions of the Software.
12
- //
13
- // THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
14
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
15
- // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17
- // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18
- // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20
- // OTHER DEALINGS IN THE SOFTWARE.
1
+ // SPDX-License-Identifier: MIT
2
+ // SPDX-FileCopyrightText: 2025 Niels Martignène <niels.martignene@protonmail.com>
21
3
 
22
4
  #pragma once
23
5
 
24
- #include "src/core/base/base.hh"
6
+ #include "lib/native/base/base.hh"
25
7
 
26
8
  #include <napi.h>
27
9
 
@@ -29,13 +11,13 @@ namespace K {
29
11
 
30
12
  static const Size DefaultSyncStackSize = Mebibytes(1);
31
13
  static const Size DefaultSyncHeapSize = Mebibytes(2);
32
- static const Size DefaultAsyncStackSize = Kibibytes(256);
33
- static const Size DefaultAsyncHeapSize = Kibibytes(512);
34
- static const int DefaultResidentAsyncPools = 2;
35
- static const int DefaultMaxAsyncCalls = 64;
14
+ static const Size DefaultAsyncStackSize = Kibibytes(128);
15
+ static const Size DefaultAsyncHeapSize = Kibibytes(128);
16
+ static const int DefaultResidentAsyncPools = 4;
17
+ static const int DefaultMaxAsyncCalls = 256;
36
18
  static const Size DefaultMaxTypeSize = Mebibytes(64);
37
19
 
38
- static const int MaxAsyncCalls = 256;
20
+ static const int MaxAsyncCalls = 4096;
39
21
  static const Size MaxParameters = 64;
40
22
  static const Size MaxTrampolines = 8192;
41
23
 
@@ -269,7 +251,7 @@ struct InstanceMemory {
269
251
 
270
252
  uint16_t generation; // Can wrap without risk
271
253
 
272
- std::atomic_bool busy;
254
+ bool busy;
273
255
  bool temporary;
274
256
  int depth;
275
257
  };
@@ -294,8 +276,8 @@ struct InstanceData {
294
276
 
295
277
  Napi::Symbol active_symbol;
296
278
 
297
- std::mutex memories_mutex;
298
- LocalArray<InstanceMemory *, 9> memories;
279
+ std::mutex mem_mutex;
280
+ LocalArray<InstanceMemory *, 17> memories;
299
281
  int temporaries = 0;
300
282
 
301
283
  std::thread::id main_thread_id;
@@ -362,6 +344,9 @@ static_assert(MaxTrampolines <= INT16_MAX);
362
344
 
363
345
  extern SharedData shared;
364
346
 
347
+ InstanceMemory *AllocateMemory(InstanceData *instance, Size stack_size, Size heap_size);
348
+ void ReleaseMemory(InstanceData *instance, InstanceMemory *mem);
349
+
365
350
  Napi::Value TranslateNormalCall(const Napi::CallbackInfo &info);
366
351
  Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info);
367
352
  Napi::Value TranslateAsyncCall(const Napi::CallbackInfo &info);