koffi 2.15.0 → 2.16.0-beta.1

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 (69) hide show
  1. package/CHANGELOG.md +7 -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/pages/index.md +4 -2
  21. package/doc/pages/misc.md +2 -0
  22. package/doc/templates/code.html +1 -2
  23. package/doc/templates/page.html +1 -2
  24. package/index.d.ts +11 -9
  25. package/index.js +9 -9
  26. package/indirect.js +9 -9
  27. package/lib/native/base/base.cc +79 -44
  28. package/lib/native/base/base.hh +31 -33
  29. package/package.json +2 -2
  30. package/src/cnoke/assets/FindCNoke.cmake +16 -10
  31. package/src/cnoke/assets/win_delay_hook.c +4 -0
  32. package/src/cnoke/src/builder.js +49 -46
  33. package/src/koffi/CMakeLists.txt +18 -8
  34. package/src/koffi/src/abi_arm32.cc +222 -219
  35. package/src/koffi/src/abi_arm32_asm.S +1 -29
  36. package/src/koffi/src/abi_arm64.cc +257 -235
  37. package/src/koffi/src/abi_arm64_asm.S +1 -32
  38. package/src/koffi/src/abi_arm64_asm.asm +1 -23
  39. package/src/koffi/src/abi_loong64_asm.S +1 -25
  40. package/src/koffi/src/abi_riscv64.cc +220 -217
  41. package/src/koffi/src/abi_riscv64_asm.S +1 -25
  42. package/src/koffi/src/abi_x64_sysv.cc +196 -192
  43. package/src/koffi/src/abi_x64_sysv_asm.S +1 -31
  44. package/src/koffi/src/abi_x64_win.cc +188 -172
  45. package/src/koffi/src/abi_x64_win_asm.S +144 -0
  46. package/src/koffi/src/abi_x64_win_asm.asm +1 -21
  47. package/src/koffi/src/abi_x86.cc +224 -189
  48. package/src/koffi/src/abi_x86_asm.S +6 -25
  49. package/src/koffi/src/abi_x86_asm.asm +9 -22
  50. package/src/koffi/src/call.cc +246 -428
  51. package/src/koffi/src/call.hh +9 -8
  52. package/src/koffi/src/ffi.cc +142 -88
  53. package/src/koffi/src/ffi.hh +13 -59
  54. package/src/koffi/src/primitives.inc +39 -0
  55. package/src/koffi/src/trampolines/armasm.inc +0 -32770
  56. package/src/koffi/src/trampolines/gnu.inc +0 -24578
  57. package/src/koffi/src/trampolines/masm32.inc +0 -32770
  58. package/src/koffi/src/trampolines/masm64.inc +0 -32770
  59. package/src/koffi/src/trampolines/prototypes.inc +16385 -16385
  60. package/src/koffi/src/util.cc +155 -112
  61. package/src/koffi/src/util.hh +77 -40
  62. package/vendor/node-api-headers/CHANGELOG.md +22 -0
  63. package/vendor/node-api-headers/README.md +6 -17
  64. package/vendor/node-api-headers/include/js_native_api.h +3 -13
  65. package/vendor/node-api-headers/include/js_native_api_types.h +15 -0
  66. package/vendor/node-api-headers/include/node_api.h +0 -4
  67. package/vendor/node-api-headers/include/node_api_types.h +6 -0
  68. package/vendor/node-api-headers/package.json +1 -1
  69. package/vendor/node-api-headers/scripts/update-headers.js +6 -0
@@ -77,8 +77,10 @@ public:
77
77
  #if defined(UNITY_BUILD)
78
78
  #if defined(_MSC_VER)
79
79
  #define INLINE_IF_UNITY __forceinline
80
- #else
80
+ #elif defined(__clang__)
81
81
  #define INLINE_IF_UNITY __attribute__((always_inline)) inline
82
+ #else
83
+ #define INLINE_IF_UNITY
82
84
  #endif
83
85
  #else
84
86
  #define INLINE_IF_UNITY
@@ -116,7 +118,7 @@ public:
116
118
 
117
119
  private:
118
120
  template <typename T>
119
- bool AllocStack(Size size, Size align, T **out_ptr);
121
+ T *AllocStack(Size size);
120
122
  template <typename T = uint8_t>
121
123
  T *AllocHeap(Size size, Size align);
122
124
 
@@ -126,15 +128,15 @@ private:
126
128
  };
127
129
 
128
130
  template <typename T>
129
- inline bool CallData::AllocStack(Size size, Size align, T **out_ptr)
131
+ inline T *CallData::AllocStack(Size size)
130
132
  {
131
- uint8_t *ptr = AlignDown(mem->stack.end() - size, align);
133
+ uint8_t *ptr = AlignDown(mem->stack.end() - size, 16);
132
134
  Size delta = mem->stack.end() - ptr;
133
135
 
134
136
  // Keep 512 bytes for redzone (required in some ABIs)
135
137
  if (mem->stack.len - 512 < delta) [[unlikely]] {
136
138
  ThrowError<Napi::Error>(env, "FFI call is taking up too much memory");
137
- return false;
139
+ return nullptr;
138
140
  }
139
141
 
140
142
  #if defined(K_DEBUG)
@@ -143,8 +145,7 @@ inline bool CallData::AllocStack(Size size, Size align, T **out_ptr)
143
145
 
144
146
  mem->stack.len -= delta;
145
147
 
146
- *out_ptr = (T *)ptr;
147
- return true;
148
+ return (T *)ptr;
148
149
  }
149
150
 
150
151
  template <typename T>
@@ -176,6 +177,6 @@ inline T *CallData::AllocHeap(Size size, Size align)
176
177
  }
177
178
  }
178
179
 
179
- void *GetTrampoline(int16_t idx, const FunctionInfo *proto);
180
+ void *GetTrampoline(int16_t idx);
180
181
 
181
182
  }
@@ -138,6 +138,20 @@ static Napi::Value GetSetConfig(const Napi::CallbackInfo &info)
138
138
  } else if (key == "max_type_size") {
139
139
  if (!ChangeSize(key.c_str(), value, 32, Mebibytes(512), &new_config.max_type_size))
140
140
  return env.Null();
141
+ } else if (key == "fast_pointers") {
142
+ if (!value.IsBoolean()) {
143
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for '%2', expected boolean", GetValueType(instance, value), key.c_str());
144
+ return env.Null();
145
+ }
146
+
147
+ new_config.fast_pointers = value.As<Napi::Boolean>();
148
+ } else if (key == "fast_callbacks") {
149
+ if (!value.IsBoolean()) {
150
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for '%2', expected boolean", GetValueType(instance, value), key.c_str());
151
+ return env.Null();
152
+ }
153
+
154
+ new_config.fast_callbacks = value.As<Napi::Boolean>();
141
155
  } else {
142
156
  ThrowError<Napi::Error>(env, "Unexpected config member '%1'", key.c_str());
143
157
  return env.Null();
@@ -162,6 +176,8 @@ static Napi::Value GetSetConfig(const Napi::CallbackInfo &info)
162
176
  obj.Set("resident_async_pools", instance->config.resident_async_pools);
163
177
  obj.Set("max_async_calls", instance->config.resident_async_pools + instance->config.max_temporaries);
164
178
  obj.Set("max_type_size", instance->config.max_type_size);
179
+ obj.Set("fast_pointers", instance->config.fast_pointers);
180
+ obj.Set("fast_callbacks", instance->config.fast_callbacks);
165
181
 
166
182
  return obj;
167
183
  }
@@ -790,13 +806,10 @@ static Napi::Value CreateDisposableType(const Napi::CallbackInfo &info)
790
806
  InstanceData *instance = env.GetInstanceData<InstanceData>();
791
807
  const Napi::FunctionReference &ref = type->dispose_ref;
792
808
 
793
- Napi::External<void> external = Napi::External<void>::New(env, (void *)ptr);
794
- SetValueTag(external, type->ref.marker);
809
+ Napi::Value p = WrapPointer(env, type->ref.type, (void *)ptr);
795
810
 
796
- Napi::Value self = env.Null();
797
- napi_value args[] = {
798
- external
799
- };
811
+ napi_value self = env.Null();
812
+ napi_value args[] = { p };
800
813
 
801
814
  ref.Call(self, K_LEN(args), args);
802
815
  instance->stats.disposed++;
@@ -842,21 +855,12 @@ static inline bool GetExternalPointer(Napi::Env env, Napi::Value value, void **o
842
855
  {
843
856
  InstanceData *instance = env.GetInstanceData<InstanceData>();
844
857
 
845
- if (IsNullOrUndefined(value)) {
846
- *out_ptr = 0;
847
- return true;
848
- } else if (value.IsExternal() && !CheckValueTag(value, &TypeInfoMarker) &&
849
- !CheckValueTag(value, &CastMarker) &&
850
- !CheckValueTag(value, &MagicUnionMarker)) {
851
- Napi::External<void> external = value.As<Napi::External<void>>();
852
- void *ptr = external.Data();
853
-
854
- *out_ptr = ptr;
855
- return true;
856
- } else {
857
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for ptr, expected external pointer", GetValueType(instance, value));
858
+ if (!TryPointer(value, out_ptr)) {
859
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for ptr, expected pointer", GetValueType(instance, value));
858
860
  return false;
859
861
  }
862
+
863
+ return true;
860
864
  }
861
865
 
862
866
  static Napi::Value CallAlloc(const Napi::CallbackInfo &info)
@@ -902,10 +906,7 @@ static Napi::Value CallAlloc(const Napi::CallbackInfo &info)
902
906
  return env.Null();
903
907
  }
904
908
 
905
- Napi::External<void> external = Napi::External<void>::New(env, ptr);
906
- SetValueTag(external, type);
907
-
908
- return external;
909
+ return WrapPointer(env, type, ptr);
909
910
  }
910
911
 
911
912
  static Napi::Value CallFree(const Napi::CallbackInfo &info)
@@ -1167,6 +1168,14 @@ static Napi::Value CreateFunctionType(const Napi::CallbackInfo &info)
1167
1168
  if (!AnalyseFunction(env, instance, func))
1168
1169
  return env.Null();
1169
1170
 
1171
+ // Branchless push loop
1172
+ for (const ParameterInfo &param: func->parameters) {
1173
+ func->primitives.Append(param.type->primitive);
1174
+ }
1175
+ if (!func->variadic) {
1176
+ func->primitives.Append(PrimitiveKind::Prototype);
1177
+ }
1178
+
1170
1179
  // Adjust parameter offsets for koffi.call()
1171
1180
  for (ParameterInfo &param: func->parameters) {
1172
1181
  param.offset += 2;
@@ -1517,62 +1526,105 @@ static Napi::Value TranslateVariadicCall(const FunctionInfo *func, void *native,
1517
1526
  Napi::Env env = info.Env();
1518
1527
  InstanceData *instance = env.GetInstanceData<InstanceData>();
1519
1528
 
1520
- FunctionInfo copy;
1521
- memcpy((void *)&copy, func, K_SIZE(*func));
1522
- copy.lib = nullptr;
1529
+ FunctionInfo *variadic = nullptr;
1530
+ K_DEFER_N(err_guard) { delete variadic; };
1523
1531
 
1524
- // This makes variadic calls non-reentrant
1525
- K_DEFER_C(len = copy.parameters.len) {
1526
- copy.parameters.RemoveFrom(len);
1527
- copy.parameters.Leak();
1528
- };
1532
+ // Try cached function
1533
+ {
1534
+ FunctionInfo *prev = instance->variadic_func;
1529
1535
 
1530
- if (info.Length() < (uint32_t)copy.required_parameters) [[unlikely]] {
1531
- ThrowError<Napi::TypeError>(env, "Expected %1 arguments or more, got %2", copy.parameters.len, info.Length());
1532
- return env.Null();
1533
- }
1534
- if ((info.Length() - copy.required_parameters) % 2) [[unlikely]] {
1535
- ThrowError<Napi::Error>(env, "Missing value argument for variadic call");
1536
- return env.Null();
1536
+ if (prev && prev->native == native) {
1537
+ Size specified = (info.Length() - prev->required_parameters);
1538
+ Size processed = (prev->parameters.len - prev->required_parameters) * 2;
1539
+
1540
+ if (specified == processed) {
1541
+ bool match = true;
1542
+
1543
+ for (Size i = prev->required_parameters, j = prev->required_parameters; i < (Size)info.Length(); i += 2, j++) {
1544
+ int directions;
1545
+ const TypeInfo *type = ResolveType(info[(uint32_t)i], &directions);
1546
+
1547
+ if (type != prev->parameters[j].type || directions != prev->parameters[j].directions) [[unlikely]] {
1548
+ match = false;
1549
+ break;
1550
+ }
1551
+ }
1552
+
1553
+ if (match) [[likely]] {
1554
+ variadic = prev;
1555
+
1556
+ // If an error happens it'll get destroyed, so don't keep it around
1557
+ instance->variadic_func = nullptr;
1558
+ }
1559
+ }
1560
+ }
1537
1561
  }
1538
1562
 
1539
- for (Size i = copy.required_parameters; i < (Size)info.Length(); i += 2) {
1540
- ParameterInfo param = {};
1563
+ if (!variadic) {
1564
+ variadic = new FunctionInfo();
1541
1565
 
1542
- param.type = ResolveType(info[(uint32_t)i], &param.directions);
1566
+ memcpy((void *)variadic, func, K_SIZE(*func));
1567
+ memset((void *)&variadic->parameters, 0, K_SIZE(variadic->parameters));
1568
+ memset((void *)&variadic->primitives, 0, K_SIZE(variadic->primitives));
1543
1569
 
1544
- if (!param.type) [[unlikely]]
1545
- return env.Null();
1546
- if (!CanPassType(param.type, param.directions)) [[unlikely]] {
1547
- ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter", param.type->name);
1570
+ variadic->parameters = func->parameters;
1571
+ variadic->primitives = func->primitives;
1572
+ variadic->lib = nullptr;
1573
+
1574
+ if (info.Length() < (uint32_t)variadic->required_parameters) [[unlikely]] {
1575
+ ThrowError<Napi::TypeError>(env, "Expected %1 arguments or more, got %2", variadic->parameters.len, info.Length());
1548
1576
  return env.Null();
1549
1577
  }
1550
- if (copy.parameters.len >= MaxParameters) [[unlikely]] {
1551
- ThrowError<Napi::TypeError>(env, "Functions cannot have more than %1 parameters", MaxParameters);
1578
+ if ((info.Length() - variadic->required_parameters) % 2) [[unlikely]] {
1579
+ ThrowError<Napi::Error>(env, "Missing value argument for variadic call");
1552
1580
  return env.Null();
1553
1581
  }
1554
- if ((param.directions & 2) && ++copy.out_parameters >= MaxParameters) [[unlikely]] {
1555
- ThrowError<Napi::TypeError>(env, "Functions cannot have more than %1 output parameters", MaxParameters);
1556
- return env.Null();
1582
+
1583
+ for (Size i = variadic->required_parameters; i < (Size)info.Length(); i += 2) {
1584
+ ParameterInfo param = {};
1585
+
1586
+ param.type = ResolveType(info[(uint32_t)i], &param.directions);
1587
+
1588
+ if (!param.type) [[unlikely]]
1589
+ return env.Null();
1590
+ if (!CanPassType(param.type, param.directions)) [[unlikely]] {
1591
+ ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter", param.type->name);
1592
+ return env.Null();
1593
+ }
1594
+ if (variadic->parameters.len >= MaxParameters) [[unlikely]] {
1595
+ ThrowError<Napi::TypeError>(env, "Functions cannot have more than %1 parameters", MaxParameters);
1596
+ return env.Null();
1597
+ }
1598
+ if ((param.directions & 2) && ++variadic->out_parameters >= MaxParameters) [[unlikely]] {
1599
+ ThrowError<Napi::TypeError>(env, "Functions cannot have more than %1 output parameters", MaxParameters);
1600
+ return env.Null();
1601
+ }
1602
+
1603
+ param.variadic = true;
1604
+ param.offset = (int8_t)(i + 1);
1605
+
1606
+ variadic->parameters.Append(param);
1557
1607
  }
1558
1608
 
1559
- param.variadic = true;
1560
- param.offset = (int8_t)(i + 1);
1609
+ if (!AnalyseFunction(env, instance, variadic)) [[unlikely]]
1610
+ return env.Null();
1561
1611
 
1562
- copy.parameters.Append(param);
1612
+ // Branchless push loop
1613
+ for (Size i = func->parameters.len; i < variadic->parameters.len; i++) {
1614
+ const ParameterInfo &param = variadic->parameters[i];
1615
+ variadic->primitives.Append(param.type->primitive);
1616
+ }
1617
+ variadic->primitives.Append(PrimitiveKind::Prototype);
1563
1618
  }
1564
1619
 
1565
- if (!AnalyseFunction(env, instance, &copy)) [[unlikely]]
1566
- return env.Null();
1567
-
1568
1620
  InstanceMemory *mem = instance->memories[0];
1569
1621
  CallData call(env, instance, mem);
1570
1622
 
1571
- if (!call.Prepare(&copy, info)) [[unlikely]]
1623
+ if (!call.Prepare(variadic, info)) [[unlikely]]
1572
1624
  return env.Null();
1573
1625
 
1574
1626
  if (instance->debug) {
1575
- call.DumpForward(&copy);
1627
+ call.DumpForward(variadic);
1576
1628
  }
1577
1629
 
1578
1630
  // Execute call
@@ -1580,10 +1632,17 @@ static Napi::Value TranslateVariadicCall(const FunctionInfo *func, void *native,
1580
1632
  K_DEFER_C(prev_call = exec_call) { exec_call = prev_call; };
1581
1633
  exec_call = &call;
1582
1634
 
1583
- call.Execute(&copy, native);
1635
+ call.Execute(variadic, native);
1584
1636
  }
1585
1637
 
1586
- return call.Complete(&copy);
1638
+ if (variadic != instance->variadic_func) {
1639
+ err_guard.Disable();
1640
+
1641
+ delete instance->variadic_func;
1642
+ instance->variadic_func = variadic;
1643
+ }
1644
+
1645
+ return call.Complete(variadic);
1587
1646
  }
1588
1647
 
1589
1648
  Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
@@ -1640,11 +1699,8 @@ void AsyncCall::OnOK()
1640
1699
 
1641
1700
  Napi::FunctionReference &callback = Callback();
1642
1701
 
1643
- Napi::Value self = env.Null();
1644
- napi_value args[] = {
1645
- env.Null(),
1646
- call.Complete(func)
1647
- };
1702
+ napi_value self = env.Null();
1703
+ napi_value args[] = { env.Null(), call.Complete(func) };
1648
1704
 
1649
1705
  callback.Call(self, K_LEN(args), args);
1650
1706
  }
@@ -1755,9 +1811,16 @@ static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info)
1755
1811
 
1756
1812
  if (!AnalyseFunction(env, instance, func))
1757
1813
  return env.Null();
1814
+
1815
+ // Branchless push loop
1816
+ for (const ParameterInfo &param: func->parameters) {
1817
+ func->primitives.Append(param.type->primitive);
1818
+ }
1758
1819
  if (func->variadic) {
1759
- // Minimize reallocations
1760
1820
  func->parameters.Grow(32);
1821
+ func->primitives.Grow(32);
1822
+ } else {
1823
+ func->primitives.Append(PrimitiveKind::Prototype);
1761
1824
  }
1762
1825
 
1763
1826
  #if defined(_WIN32)
@@ -1822,10 +1885,7 @@ static Napi::Value FindSymbol(const Napi::CallbackInfo &info)
1822
1885
  return env.Null();
1823
1886
  }
1824
1887
 
1825
- Napi::External<void> external = Napi::External<void>::New(env, ptr);
1826
- SetValueTag(external, &type);
1827
-
1828
- return external;
1888
+ return WrapPointer(env, type, ptr);
1829
1889
  }
1830
1890
 
1831
1891
  static Napi::Value UnloadLibrary(const Napi::CallbackInfo &info)
@@ -1992,15 +2052,12 @@ static Napi::Value RegisterCallback(const Napi::CallbackInfo &info)
1992
2052
  }
1993
2053
  trampoline->generation = -1;
1994
2054
 
1995
- void *ptr = GetTrampoline(idx, type->ref.proto);
1996
-
1997
- Napi::External<void> external = Napi::External<void>::New(env, ptr);
1998
- SetValueTag(external, type->ref.marker);
2055
+ void *ptr = GetTrampoline(idx);
1999
2056
 
2000
2057
  // Cache index for fast unregistration
2001
2058
  instance->trampolines_map.Set(ptr, idx);
2002
2059
 
2003
- return external;
2060
+ return WrapCallback(env, type->ref.type, ptr);
2004
2061
  }
2005
2062
 
2006
2063
  static Napi::Value UnregisterCallback(const Napi::CallbackInfo &info)
@@ -2012,14 +2069,13 @@ static Napi::Value UnregisterCallback(const Napi::CallbackInfo &info)
2012
2069
  ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
2013
2070
  return env.Null();
2014
2071
  }
2015
- if (!info[0].IsExternal()) {
2072
+
2073
+ void *ptr;
2074
+ if (!TryPointer(info[0], &ptr)) {
2016
2075
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for id, expected registered callback", GetValueType(instance, info[0]));
2017
2076
  return env.Null();
2018
2077
  }
2019
2078
 
2020
- Napi::External<void> external = info[0].As<Napi::External<void>>();
2021
- void *ptr = external.Data();
2022
-
2023
2079
  int16_t idx;
2024
2080
  {
2025
2081
  int16_t *it = instance->trampolines_map.Find(ptr);
@@ -2375,10 +2431,8 @@ static void RegisterPrimitiveType(Napi::Env env, Napi::Object map, std::initiali
2375
2431
  }
2376
2432
 
2377
2433
  if (ref) {
2378
- const TypeInfo *marker = instance->types_map.FindValue(ref, nullptr);
2379
- K_ASSERT(marker);
2380
-
2381
- type->ref.marker = marker;
2434
+ type->ref.type = instance->types_map.FindValue(ref, nullptr);
2435
+ K_ASSERT(type->ref.type);
2382
2436
  }
2383
2437
 
2384
2438
  Napi::Value wrapper = WrapType(env, type);
@@ -2582,7 +2636,8 @@ static Napi::Object InitModule(Napi::Env env, Napi::Object exports)
2582
2636
  instance->str16_type = instance->types_map.FindValue("char16_t *", nullptr);
2583
2637
  instance->str32_type = instance->types_map.FindValue("char32_t *", nullptr);
2584
2638
 
2585
- instance->active_symbol = Napi::Symbol::New(env, "active");
2639
+ Napi::Symbol symbol = Napi::Symbol::New(env, "active");
2640
+ instance->active_symbol.Reset(symbol, 1);
2586
2641
 
2587
2642
  instance->base_types_count = instance->types.count;
2588
2643
  }
@@ -2592,10 +2647,7 @@ static Napi::Object InitModule(Napi::Env env, Napi::Object exports)
2592
2647
  Napi::Object node = Napi::Object::New(env);
2593
2648
  exports.Set("node", node);
2594
2649
 
2595
- Napi::External<void> external = Napi::External<void>::New(env, (napi_env)env);
2596
- SetValueTag(external, instance->void_type);
2597
-
2598
- node.Set("env", external);
2650
+ node.Set("env", WrapPointer(env, instance->void_type, (napi_env)env));
2599
2651
 
2600
2652
  node.Set("poll", Napi::Function::New(env, &Poll, "poll"));
2601
2653
  node.Set("PollHandle", PollHandle::Define(env));
@@ -2608,6 +2660,8 @@ static Napi::Object InitModule(Napi::Env env, Napi::Object exports)
2608
2660
 
2609
2661
  InstanceData::~InstanceData()
2610
2662
  {
2663
+ delete variadic_func;
2664
+
2611
2665
  for (InstanceMemory *mem: memories) {
2612
2666
  delete mem;
2613
2667
  }
@@ -22,64 +22,12 @@ 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
 
85
33
  struct TypeInfo;
@@ -109,7 +57,7 @@ static const char *const ArrayHintNames[] = {
109
57
  struct TypeInfo {
110
58
  const char *name;
111
59
 
112
- // Make sure primitie ends up as the upper N-API tag value when we cast TypeInfo pointers to
60
+ // Make sure primitive ends up as the upper N-API tag value when we cast TypeInfo pointers to
113
61
  // napi_type_tag pointers. Yes, I want to do this. We don't do strict aliasing here.
114
62
  // N.B. Some node versions don't like when one of the two tag values is 0, so make sure
115
63
  // this does not happen! It would happen if primitive is 0 and size is 0. To avoid this
@@ -124,7 +72,6 @@ struct TypeInfo {
124
72
 
125
73
  HeapArray<RecordMember> members; // Record only
126
74
  union {
127
- const void *marker;
128
75
  const TypeInfo *type; // Pointer or array
129
76
  const FunctionInfo *proto; // Callback only
130
77
  } ref;
@@ -223,6 +170,7 @@ struct FunctionInfo {
223
170
 
224
171
  ParameterInfo ret;
225
172
  HeapArray<ParameterInfo> parameters;
173
+ HeapArray<PrimitiveKind> primitives;
226
174
  int8_t required_parameters;
227
175
  int8_t out_parameters;
228
176
  bool variadic;
@@ -274,12 +222,15 @@ struct InstanceData {
274
222
  const TypeInfo *str16_type;
275
223
  const TypeInfo *str32_type;
276
224
 
277
- Napi::Symbol active_symbol;
225
+ Napi::Reference<Napi::Symbol> active_symbol;
278
226
 
279
227
  std::mutex mem_mutex;
280
228
  LocalArray<InstanceMemory *, 17> memories;
281
229
  int temporaries = 0;
282
230
 
231
+ // Variadic cache
232
+ FunctionInfo *variadic_func = nullptr;
233
+
283
234
  std::thread::id main_thread_id;
284
235
  napi_threadsafe_function broker = nullptr;
285
236
 
@@ -305,6 +256,9 @@ struct InstanceData {
305
256
  int resident_async_pools = DefaultResidentAsyncPools;
306
257
  int max_temporaries = DefaultMaxAsyncCalls - DefaultResidentAsyncPools;
307
258
  Size max_type_size = DefaultMaxTypeSize;
259
+
260
+ bool fast_pointers = false;
261
+ bool fast_callbacks = false;
308
262
  } config;
309
263
 
310
264
  struct {
@@ -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