koffi 2.4.2 → 2.5.0-beta.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 (63) hide show
  1. package/build/2.5.0-beta.2/koffi_darwin_arm64/koffi.node +0 -0
  2. package/build/2.5.0-beta.2/koffi_darwin_x64/koffi.node +0 -0
  3. package/build/2.5.0-beta.2/koffi_freebsd_arm64/koffi.node +0 -0
  4. package/build/2.5.0-beta.2/koffi_freebsd_ia32/koffi.node +0 -0
  5. package/build/2.5.0-beta.2/koffi_freebsd_x64/koffi.node +0 -0
  6. package/build/2.5.0-beta.2/koffi_linux_arm32hf/koffi.node +0 -0
  7. package/build/2.5.0-beta.2/koffi_linux_arm64/koffi.node +0 -0
  8. package/build/2.5.0-beta.2/koffi_linux_ia32/koffi.node +0 -0
  9. package/build/2.5.0-beta.2/koffi_linux_riscv64hf64/koffi.node +0 -0
  10. package/build/2.5.0-beta.2/koffi_linux_x64/koffi.node +0 -0
  11. package/build/2.5.0-beta.2/koffi_openbsd_ia32/koffi.node +0 -0
  12. package/build/{2.4.2 → 2.5.0-beta.2}/koffi_openbsd_x64/koffi.node +0 -0
  13. package/build/2.5.0-beta.2/koffi_win32_arm64/koffi.node +0 -0
  14. package/build/{2.4.2 → 2.5.0-beta.2}/koffi_win32_ia32/koffi.node +0 -0
  15. package/build/{2.4.2 → 2.5.0-beta.2}/koffi_win32_x64/koffi.node +0 -0
  16. package/build/2.5.0-beta.2/koffi_win32_x64/koffi.pdb +0 -0
  17. package/doc/callbacks.md +1 -1
  18. package/doc/conf.py +1 -1
  19. package/doc/functions.md +1 -1
  20. package/doc/index.rst +1 -0
  21. package/doc/parameters.md +1 -1
  22. package/doc/pointers.md +1 -1
  23. package/doc/unions.md +187 -0
  24. package/package.json +1 -1
  25. package/src/core/libcc/libcc.cc +58 -54
  26. package/src/core/libcc/libcc.hh +33 -19
  27. package/src/koffi/src/abi_x86.cc +31 -4
  28. package/src/koffi/src/call.cc +42 -22
  29. package/src/koffi/src/ffi.cc +259 -311
  30. package/src/koffi/src/ffi.hh +3 -1
  31. package/src/koffi/src/util.cc +20 -13
  32. package/src/koffi/src/util.hh +5 -2
  33. package/vendor/node-addon-api/CHANGELOG.md +31 -0
  34. package/vendor/node-addon-api/README.md +3 -2
  35. package/vendor/node-addon-api/doc/async_worker.md +1 -0
  36. package/vendor/node-addon-api/doc/creating_a_release.md +21 -0
  37. package/vendor/node-addon-api/doc/value.md +7 -0
  38. package/vendor/node-addon-api/napi-inl.h +23 -7
  39. package/vendor/node-addon-api/package.json +9 -1
  40. package/vendor/node-addon-api/test/async_progress_queue_worker.cc +155 -0
  41. package/vendor/node-addon-api/test/async_progress_queue_worker.js +134 -0
  42. package/vendor/node-addon-api/test/async_progress_worker.cc +155 -0
  43. package/vendor/node-addon-api/test/async_progress_worker.js +134 -0
  44. package/vendor/node-addon-api/test/common/index.js +45 -0
  45. package/vendor/node-addon-api/test/objectwrap.js +9 -0
  46. package/build/2.4.2/koffi_darwin_arm64/koffi.node +0 -0
  47. package/build/2.4.2/koffi_darwin_x64/koffi.node +0 -0
  48. package/build/2.4.2/koffi_freebsd_arm64/koffi.node +0 -0
  49. package/build/2.4.2/koffi_freebsd_ia32/koffi.node +0 -0
  50. package/build/2.4.2/koffi_freebsd_x64/koffi.node +0 -0
  51. package/build/2.4.2/koffi_linux_arm32hf/koffi.node +0 -0
  52. package/build/2.4.2/koffi_linux_arm64/koffi.node +0 -0
  53. package/build/2.4.2/koffi_linux_ia32/koffi.node +0 -0
  54. package/build/2.4.2/koffi_linux_riscv64hf64/koffi.node +0 -0
  55. package/build/2.4.2/koffi_linux_x64/koffi.node +0 -0
  56. package/build/2.4.2/koffi_openbsd_ia32/koffi.node +0 -0
  57. package/build/2.4.2/koffi_win32_arm64/koffi.node +0 -0
  58. /package/build/{2.4.2 → 2.5.0-beta.2}/koffi_win32_arm64/koffi.exp +0 -0
  59. /package/build/{2.4.2 → 2.5.0-beta.2}/koffi_win32_arm64/koffi.lib +0 -0
  60. /package/build/{2.4.2 → 2.5.0-beta.2}/koffi_win32_ia32/koffi.exp +0 -0
  61. /package/build/{2.4.2 → 2.5.0-beta.2}/koffi_win32_ia32/koffi.lib +0 -0
  62. /package/build/{2.4.2 → 2.5.0-beta.2}/koffi_win32_x64/koffi.exp +0 -0
  63. /package/build/{2.4.2 → 2.5.0-beta.2}/koffi_win32_x64/koffi.lib +0 -0
@@ -134,7 +134,7 @@ static Napi::Value GetSetConfig(const Napi::CallbackInfo &info)
134
134
  Napi::Array keys = obj.GetPropertyNames();
135
135
 
136
136
  for (uint32_t i = 0; i < keys.Length(); i++) {
137
- std::string key = ((Napi::Value)keys[i]).As<Napi::String>();
137
+ std::string key = keys.Get(i).As<Napi::String>();
138
138
  Napi::Value value = obj[key];
139
139
 
140
140
  if (key == "sync_stack_size") {
@@ -243,7 +243,7 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
243
243
  for (uint32_t i = 0; i < keys.Length(); i++) {
244
244
  RecordMember member = {};
245
245
 
246
- std::string key = ((Napi::Value)keys[i]).As<Napi::String>();
246
+ std::string key = keys.Get(i).As<Napi::String>();
247
247
  Napi::Value value = obj[key];
248
248
  int16_t align = 0;
249
249
 
@@ -252,12 +252,12 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
252
252
  if (value.IsArray()) {
253
253
  Napi::Array array = value.As<Napi::Array>();
254
254
 
255
- if (array.Length() != 2 || !((Napi::Value)array[0u]).IsNumber()) {
255
+ if (array.Length() != 2 || !array.Get(0u).IsNumber()) {
256
256
  ThrowError<Napi::Error>(env, "Member specifier array must contain alignement value and type");
257
257
  return env.Null();
258
258
  }
259
259
 
260
- int64_t align64 = ((Napi::Value)array[0u]).As<Napi::Number>().Int64Value();
260
+ int64_t align64 = array.Get(0u).As<Napi::Number>().Int64Value();
261
261
 
262
262
  if (!CheckAlignment(align64)) {
263
263
  ThrowError<Napi::Error>(env, "Alignment of member '%1' must be 1, 2, 4 or 8", member.name);
@@ -371,7 +371,7 @@ static Napi::Value CreateUnionType(const Napi::CallbackInfo &info)
371
371
  for (uint32_t i = 0; i < keys.Length(); i++) {
372
372
  RecordMember member = {};
373
373
 
374
- std::string key = ((Napi::Value)keys[i]).As<Napi::String>();
374
+ std::string key = keys.Get(i).As<Napi::String>();
375
375
  Napi::Value value = obj[key];
376
376
  int16_t align = 0;
377
377
 
@@ -380,12 +380,12 @@ static Napi::Value CreateUnionType(const Napi::CallbackInfo &info)
380
380
  if (value.IsArray()) {
381
381
  Napi::Array array = value.As<Napi::Array>();
382
382
 
383
- if (array.Length() != 2 || !((Napi::Value)array[0u]).IsNumber()) {
383
+ if (array.Length() != 2 || !array.Get(0u).IsNumber()) {
384
384
  ThrowError<Napi::Error>(env, "Member specifier array must contain alignement value and type");
385
385
  return env.Null();
386
386
  }
387
387
 
388
- int64_t align64 = ((Napi::Value)array[0u]).As<Napi::Number>().Int64Value();
388
+ int64_t align64 = array.Get(0u).As<Napi::Number>().Int64Value();
389
389
 
390
390
  if (!CheckAlignment(align64)) {
391
391
  ThrowError<Napi::Error>(env, "Alignment of member '%1' must be 1, 2, 4 or 8", member.name);
@@ -879,7 +879,7 @@ static bool ParseClassicFunction(Napi::Env env, Napi::String name, Napi::Value r
879
879
  uint32_t parameters_len = parameters.Length();
880
880
 
881
881
  if (parameters_len) {
882
- Napi::String str = ((Napi::Value)parameters[parameters_len - 1]).As<Napi::String>();
882
+ Napi::String str = parameters.Get(parameters_len - 1).As<Napi::String>();
883
883
 
884
884
  if (str.IsString() && str.Utf8Value() == "...") {
885
885
  func->variadic = true;
@@ -993,12 +993,15 @@ static Napi::Value CreateTypeAlias(const Napi::CallbackInfo &info)
993
993
  if (!type)
994
994
  return env.Null();
995
995
 
996
- bool inserted;
997
- instance->types_map.TrySet(alias, type, &inserted);
996
+ // Alias the type
997
+ {
998
+ bool inserted;
999
+ instance->types_map.TrySet(alias, type, &inserted);
998
1000
 
999
- if (!inserted) {
1000
- ThrowError<Napi::Error>(env, "Type name '%1' already exists", alias);
1001
- return env.Null();
1001
+ if (!inserted) {
1002
+ ThrowError<Napi::Error>(env, "Type name '%1' already exists", alias);
1003
+ return env.Null();
1004
+ }
1002
1005
  }
1003
1006
 
1004
1007
  return WrapType(env, instance, type);
@@ -1451,6 +1454,35 @@ Napi::Value TranslateAsyncCall(const Napi::CallbackInfo &info)
1451
1454
  return TranslateAsyncCall(func, func->native, info);
1452
1455
  }
1453
1456
 
1457
+ extern "C" void RelayCallback(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
1458
+ {
1459
+ if (RG_LIKELY(exec_call)) {
1460
+ exec_call->RelaySafe(idx, own_sp, caller_sp, false, out_reg);
1461
+ } else {
1462
+ // This happens if the callback pointer is called from a different thread
1463
+ // than the one that runs the FFI call (sync or async).
1464
+
1465
+ TrampolineInfo *trampoline = &shared.trampolines[idx];
1466
+
1467
+ Napi::Env env = trampoline->func.Env();
1468
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
1469
+
1470
+ InstanceMemory *mem = AllocateMemory(instance, instance->config.async_stack_size, instance->config.async_heap_size);
1471
+ if (RG_UNLIKELY(!mem)) {
1472
+ ThrowError<Napi::Error>(env, "Too many asynchronous calls are running");
1473
+ return;
1474
+ }
1475
+
1476
+ // Avoid triggering the "use callback beyond FFI" check
1477
+ RG_DEFER_C(generation = trampoline->generation) { trampoline->generation = generation; };
1478
+ trampoline->generation = -1;
1479
+
1480
+ // We set dispose_call to true so that the main thread will dispose of CallData itself
1481
+ CallData call(env, instance, mem);
1482
+ call.RelaySafe(idx, own_sp, caller_sp, true, out_reg);
1483
+ }
1484
+ }
1485
+
1454
1486
  static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info, CallConvention convention)
1455
1487
  {
1456
1488
  Napi::Env env = info.Env();
@@ -1725,6 +1757,116 @@ static Napi::Value UnregisterCallback(const Napi::CallbackInfo &info)
1725
1757
  return env.Undefined();
1726
1758
  }
1727
1759
 
1760
+ static Napi::Value CastValue(const Napi::CallbackInfo &info)
1761
+ {
1762
+ Napi::Env env = info.Env();
1763
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
1764
+
1765
+ if (RG_UNLIKELY(info.Length() < 2)) {
1766
+ ThrowError<Napi::TypeError>(env, "Expected 2 arguments, got %1", info.Length());
1767
+ return env.Null();
1768
+ }
1769
+
1770
+ Napi::Value value = info[0];
1771
+
1772
+ const TypeInfo *type = ResolveType(info[1]);
1773
+ if (RG_UNLIKELY(!type))
1774
+ return env.Null();
1775
+ if (type->primitive != PrimitiveKind::Pointer &&
1776
+ type->primitive != PrimitiveKind::String &&
1777
+ type->primitive != PrimitiveKind::String16) {
1778
+ ThrowError<Napi::TypeError>(env, "Only pointer or string types can be used for casting");
1779
+ return env.Null();
1780
+ }
1781
+
1782
+ ValueCast *cast = new ValueCast;
1783
+
1784
+ cast->ref.Reset(value, 1);
1785
+ cast->type = type;
1786
+
1787
+ Napi::External<ValueCast> external = Napi::External<ValueCast>::New(env, cast, [](Napi::Env, ValueCast *cast) { delete cast; });
1788
+ SetValueTag(instance, external, &CastMarker);
1789
+
1790
+ return external;
1791
+ }
1792
+
1793
+ static Napi::Value DecodeValue(const Napi::CallbackInfo &info)
1794
+ {
1795
+ Napi::Env env = info.Env();
1796
+
1797
+ bool has_offset = (info.Length() >= 2 && info[1].IsNumber());
1798
+ bool has_len = (info.Length() >= 3u + has_offset && info[2u + has_offset].IsNumber());
1799
+
1800
+ if (RG_UNLIKELY(info.Length() < 2u + has_offset)) {
1801
+ ThrowError<Napi::TypeError>(env, "Expected %1 to 4 arguments, got %2", 2 + has_offset, info.Length());
1802
+ return env.Null();
1803
+ }
1804
+
1805
+ const TypeInfo *type = ResolveType(info[1u + has_offset]);
1806
+ if (RG_UNLIKELY(!type))
1807
+ return env.Null();
1808
+
1809
+ Napi::Value value = info[0];
1810
+ int64_t offset = has_offset ? info[1].As<Napi::Number>().Int64Value() : 0;
1811
+
1812
+ if (has_len) {
1813
+ Size len = info[2u + has_offset].As<Napi::Number>();
1814
+
1815
+ Napi::Value ret = Decode(value, offset, type, &len);
1816
+ return ret;
1817
+ } else {
1818
+ Napi::Value ret = Decode(value, offset, type);
1819
+ return ret;
1820
+ }
1821
+ }
1822
+
1823
+ static Napi::Value GetPointerAddress(const Napi::CallbackInfo &info)
1824
+ {
1825
+ Napi::Env env = info.Env();
1826
+
1827
+ if (info.Length() < 1) {
1828
+ ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
1829
+ return env.Null();
1830
+ }
1831
+
1832
+ void *ptr = nullptr;
1833
+ if (!GetExternalPointer(env, info[0], &ptr))
1834
+ return env.Null();
1835
+
1836
+ uint64_t ptr64 = (uint64_t)(uintptr_t)ptr;
1837
+ Napi::BigInt bigint = Napi::BigInt::New(env, ptr64);
1838
+
1839
+ return bigint;
1840
+ }
1841
+
1842
+ static Napi::Value CallPointerSync(const Napi::CallbackInfo &info)
1843
+ {
1844
+ Napi::Env env = info.Env();
1845
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
1846
+
1847
+ if (RG_UNLIKELY(info.Length() < 2)) {
1848
+ ThrowError<Napi::TypeError>(env, "Expected 2 or more arguments, got %1", info.Length());
1849
+ return env.Null();
1850
+ }
1851
+
1852
+ void *ptr = nullptr;
1853
+ if (RG_UNLIKELY(!GetExternalPointer(env, info[0], &ptr)))
1854
+ return env.Null();
1855
+
1856
+ const TypeInfo *type = ResolveType(info[1]);
1857
+ if (RG_UNLIKELY(!type))
1858
+ return env.Null();
1859
+ if (RG_UNLIKELY(type->primitive != PrimitiveKind::Prototype)) {
1860
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for type, expected function type", GetValueType(instance, info[1]));
1861
+ return env.Null();
1862
+ }
1863
+
1864
+ const FunctionInfo *proto = type->ref.proto;
1865
+
1866
+ return proto->variadic ? TranslateVariadicCall(proto, ptr, info)
1867
+ : TranslateNormalCall(proto, ptr, info);
1868
+ }
1869
+
1728
1870
  void LibraryHolder::Unload()
1729
1871
  {
1730
1872
  #ifdef _WIN32
@@ -1753,6 +1895,45 @@ void LibraryHolder::Unref() const
1753
1895
  }
1754
1896
  }
1755
1897
 
1898
+ FunctionInfo::~FunctionInfo()
1899
+ {
1900
+ if (lib) {
1901
+ lib->Unref();
1902
+ }
1903
+ }
1904
+
1905
+ const FunctionInfo *FunctionInfo::Ref() const
1906
+ {
1907
+ refcount++;
1908
+ return this;
1909
+ }
1910
+
1911
+ void FunctionInfo::Unref() const
1912
+ {
1913
+ if (!--refcount) {
1914
+ delete this;
1915
+ }
1916
+ }
1917
+
1918
+ InstanceMemory::~InstanceMemory()
1919
+ {
1920
+ #ifdef _WIN32
1921
+ if (stack.ptr) {
1922
+ VirtualFree(stack.ptr, 0, MEM_RELEASE);
1923
+ }
1924
+ if (heap.ptr) {
1925
+ VirtualFree(heap.ptr, 0, MEM_RELEASE);
1926
+ }
1927
+ #else
1928
+ if (stack.ptr) {
1929
+ munmap(stack.ptr, stack.len);
1930
+ }
1931
+ if (heap.ptr) {
1932
+ munmap(heap.ptr, heap.len);
1933
+ }
1934
+ #endif
1935
+ }
1936
+
1756
1937
  static void RegisterPrimitiveType(Napi::Env env, Napi::Object map, std::initializer_list<const char *> names,
1757
1938
  PrimitiveKind primitive, int32_t size, int16_t align, const char *ref = nullptr)
1758
1939
  {
@@ -1877,50 +2058,13 @@ static Napi::Object InitBaseTypes(Napi::Env env)
1877
2058
  instance->char_type = instance->types_map.FindValue("char", nullptr);
1878
2059
  instance->char16_type = instance->types_map.FindValue("char16", nullptr);
1879
2060
 
2061
+ instance->active_symbol = Napi::Symbol::New(env, "active");
2062
+
1880
2063
  types.Freeze();
1881
2064
 
1882
2065
  return types;
1883
2066
  }
1884
2067
 
1885
- FunctionInfo::~FunctionInfo()
1886
- {
1887
- if (lib) {
1888
- lib->Unref();
1889
- }
1890
- }
1891
-
1892
- const FunctionInfo *FunctionInfo::Ref() const
1893
- {
1894
- refcount++;
1895
- return this;
1896
- }
1897
-
1898
- void FunctionInfo::Unref() const
1899
- {
1900
- if (!--refcount) {
1901
- delete this;
1902
- }
1903
- }
1904
-
1905
- InstanceMemory::~InstanceMemory()
1906
- {
1907
- #ifdef _WIN32
1908
- if (stack.ptr) {
1909
- VirtualFree(stack.ptr, 0, MEM_RELEASE);
1910
- }
1911
- if (heap.ptr) {
1912
- VirtualFree(heap.ptr, 0, MEM_RELEASE);
1913
- }
1914
- #else
1915
- if (stack.ptr) {
1916
- munmap(stack.ptr, stack.len);
1917
- }
1918
- if (heap.ptr) {
1919
- munmap(heap.ptr, heap.len);
1920
- }
1921
- #endif
1922
- }
1923
-
1924
2068
  static InstanceData *CreateInstance(Napi::Env env)
1925
2069
  {
1926
2070
  InstanceData *instance = new InstanceData();
@@ -1928,6 +2072,9 @@ static InstanceData *CreateInstance(Napi::Env env)
1928
2072
 
1929
2073
  instance->main_thread_id = std::this_thread::get_id();
1930
2074
 
2075
+ instance->debug = GetDebugFlag("DUMP_CALLS");
2076
+ FillRandomSafe(&instance->tag_lower, RG_SIZE(instance->tag_lower));
2077
+
1931
2078
  if (napi_create_threadsafe_function(env, nullptr, nullptr,
1932
2079
  Napi::String::New(env, "Koffi Async Callback Broker"),
1933
2080
  0, 1, nullptr, nullptr, nullptr,
@@ -1948,214 +2095,53 @@ static InstanceData *CreateInstance(Napi::Env env)
1948
2095
  return instance;
1949
2096
  }
1950
2097
 
1951
- InstanceData::~InstanceData()
1952
- {
1953
- for (InstanceMemory *mem: memories) {
1954
- delete mem;
1955
- }
1956
-
1957
- // Clean-up leftover trampoline references
1958
- {
1959
- std::lock_guard<std::mutex> lock(shared.mutex);
1960
-
1961
- for (int16_t idx = 0; idx < MaxTrampolines; idx++) {
1962
- TrampolineInfo *trampoline = &shared.trampolines[idx];
1963
-
1964
- if (trampoline->instance == this) {
1965
- trampoline->instance = nullptr;
1966
- trampoline->func.Reset();
1967
- trampoline->recv.Reset();
1968
- }
1969
- }
1970
- }
1971
-
1972
- if (broker) {
1973
- napi_release_threadsafe_function(broker, napi_tsfn_abort);
1974
- }
1975
- }
1976
-
1977
- static Napi::Value CastValue(const Napi::CallbackInfo &info)
1978
- {
1979
- Napi::Env env = info.Env();
1980
- InstanceData *instance = env.GetInstanceData<InstanceData>();
1981
-
1982
- if (RG_UNLIKELY(info.Length() < 2)) {
1983
- ThrowError<Napi::TypeError>(env, "Expected 2 arguments, got %1", info.Length());
1984
- return env.Null();
1985
- }
1986
-
1987
- Napi::Value value = info[0];
1988
-
1989
- const TypeInfo *type = ResolveType(info[1]);
1990
- if (RG_UNLIKELY(!type))
1991
- return env.Null();
1992
- if (type->primitive != PrimitiveKind::Pointer &&
1993
- type->primitive != PrimitiveKind::String &&
1994
- type->primitive != PrimitiveKind::String16) {
1995
- ThrowError<Napi::TypeError>(env, "Only pointer or string types can be used for casting");
1996
- return env.Null();
1997
- }
1998
-
1999
- ValueCast *cast = new ValueCast;
2000
-
2001
- cast->ref.Reset(value, 1);
2002
- cast->type = type;
2003
-
2004
- Napi::External<ValueCast> external = Napi::External<ValueCast>::New(env, cast, [](Napi::Env, ValueCast *cast) { delete cast; });
2005
- SetValueTag(instance, external, &CastMarker);
2006
-
2007
- return external;
2008
- }
2009
-
2010
- static Napi::Value DecodeValue(const Napi::CallbackInfo &info)
2011
- {
2012
- Napi::Env env = info.Env();
2013
-
2014
- bool has_offset = (info.Length() >= 2 && info[1].IsNumber());
2015
- bool has_len = (info.Length() >= 3u + has_offset && info[2u + has_offset].IsNumber());
2016
-
2017
- if (RG_UNLIKELY(info.Length() < 2u + has_offset)) {
2018
- ThrowError<Napi::TypeError>(env, "Expected %1 to 4 arguments, got %2", 2 + has_offset, info.Length());
2019
- return env.Null();
2020
- }
2021
-
2022
- const TypeInfo *type = ResolveType(info[1u + has_offset]);
2023
- if (RG_UNLIKELY(!type))
2024
- return env.Null();
2025
-
2026
- Napi::Value value = info[0];
2027
- int64_t offset = has_offset ? info[1].As<Napi::Number>().Int64Value() : 0;
2028
-
2029
- if (has_len) {
2030
- Size len = info[2u + has_offset].As<Napi::Number>();
2031
-
2032
- Napi::Value ret = Decode(value, offset, type, &len);
2033
- return ret;
2034
- } else {
2035
- Napi::Value ret = Decode(value, offset, type);
2036
- return ret;
2037
- }
2038
- }
2039
-
2040
- static Napi::Value GetPointerAddress(const Napi::CallbackInfo &info)
2041
- {
2042
- Napi::Env env = info.Env();
2043
-
2044
- if (info.Length() < 1) {
2045
- ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
2046
- return env.Null();
2047
- }
2048
-
2049
- void *ptr = nullptr;
2050
- if (!GetExternalPointer(env, info[0], &ptr))
2051
- return env.Null();
2052
-
2053
- uint64_t ptr64 = (uint64_t)(uintptr_t)ptr;
2054
- Napi::BigInt bigint = Napi::BigInt::New(env, ptr64);
2055
-
2056
- return bigint;
2057
- }
2058
-
2059
- static Napi::Value CallPointerSync(const Napi::CallbackInfo &info)
2060
- {
2061
- Napi::Env env = info.Env();
2062
- InstanceData *instance = env.GetInstanceData<InstanceData>();
2063
-
2064
- if (RG_UNLIKELY(info.Length() < 2)) {
2065
- ThrowError<Napi::TypeError>(env, "Expected 2 or more arguments, got %1", info.Length());
2066
- return env.Null();
2067
- }
2068
-
2069
- void *ptr = nullptr;
2070
- if (RG_UNLIKELY(!GetExternalPointer(env, info[0], &ptr)))
2071
- return env.Null();
2072
-
2073
- const TypeInfo *type = ResolveType(info[1]);
2074
- if (RG_UNLIKELY(!type))
2075
- return env.Null();
2076
- if (RG_UNLIKELY(type->primitive != PrimitiveKind::Prototype)) {
2077
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for type, expected function type", GetValueType(instance, info[1]));
2078
- return env.Null();
2079
- }
2080
-
2081
- const FunctionInfo *proto = type->ref.proto;
2082
-
2083
- return proto->variadic ? TranslateVariadicCall(proto, ptr, info)
2084
- : TranslateNormalCall(proto, ptr, info);
2085
- }
2086
-
2087
- extern "C" void RelayCallback(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
2098
+ static Napi::Object InitModule(Napi::Env env, Napi::Object exports)
2088
2099
  {
2089
- if (RG_LIKELY(exec_call)) {
2090
- exec_call->RelaySafe(idx, own_sp, caller_sp, false, out_reg);
2091
- } else {
2092
- // This happens if the callback pointer is called from a different thread
2093
- // than the one that runs the FFI call (sync or async).
2094
-
2095
- TrampolineInfo *trampoline = &shared.trampolines[idx];
2096
-
2097
- Napi::Env env = trampoline->func.Env();
2098
- InstanceData *instance = env.GetInstanceData<InstanceData>();
2099
-
2100
- InstanceMemory *mem = AllocateMemory(instance, instance->config.async_stack_size, instance->config.async_heap_size);
2101
- if (RG_UNLIKELY(!mem)) {
2102
- ThrowError<Napi::Error>(env, "Too many asynchronous calls are running");
2103
- return;
2104
- }
2105
-
2106
- // Avoid triggering the "use callback beyond FFI" check
2107
- RG_DEFER_C(generation = trampoline->generation) { trampoline->generation = generation; };
2108
- trampoline->generation = -1;
2100
+ InstanceData *instance = CreateInstance(env);
2101
+ RG_CRITICAL(instance, "Failed to initialize Koffi");
2109
2102
 
2110
- // We set dispose_call to true so that the main thread will dispose of CallData itself
2111
- CallData call(env, instance, mem);
2112
- call.RelaySafe(idx, own_sp, caller_sp, true, out_reg);
2113
- }
2114
- }
2103
+ env.SetInstanceData(instance);
2115
2104
 
2116
- template <typename Func>
2117
- static void SetExports(Napi::Env env, Func func)
2118
- {
2119
- func("config", Napi::Function::New(env, GetSetConfig));
2120
- func("stats", Napi::Function::New(env, GetStats));
2105
+ exports.Set("config", Napi::Function::New(env, GetSetConfig));
2106
+ exports.Set("stats", Napi::Function::New(env, GetStats));
2121
2107
 
2122
- func("struct", Napi::Function::New(env, CreatePaddedStructType));
2123
- func("pack", Napi::Function::New(env, CreatePackedStructType));
2124
- // func("union", Napi::Function::New(env, CreateUnionType));
2125
- // func("Union", Napi::Function::New(env, InstantiateUnion));
2126
- func("opaque", Napi::Function::New(env, CreateOpaqueType));
2127
- func("pointer", Napi::Function::New(env, CreatePointerType));
2128
- func("array", Napi::Function::New(env, CreateArrayType));
2129
- func("proto", Napi::Function::New(env, CreateFunctionType));
2130
- func("alias", Napi::Function::New(env, CreateTypeAlias));
2108
+ exports.Set("struct", Napi::Function::New(env, CreatePaddedStructType));
2109
+ exports.Set("pack", Napi::Function::New(env, CreatePackedStructType));
2110
+ exports.Set("union", Napi::Function::New(env, CreateUnionType));
2111
+ exports.Set("Union", Napi::Function::New(env, InstantiateUnion));
2112
+ exports.Set("opaque", Napi::Function::New(env, CreateOpaqueType));
2113
+ exports.Set("pointer", Napi::Function::New(env, CreatePointerType));
2114
+ exports.Set("array", Napi::Function::New(env, CreateArrayType));
2115
+ exports.Set("proto", Napi::Function::New(env, CreateFunctionType));
2116
+ exports.Set("alias", Napi::Function::New(env, CreateTypeAlias));
2131
2117
 
2132
- func("sizeof", Napi::Function::New(env, GetTypeSize));
2133
- func("alignof", Napi::Function::New(env, GetTypeAlign));
2134
- func("offsetof", Napi::Function::New(env, GetMemberOffset));
2135
- func("resolve", Napi::Function::New(env, GetResolvedType));
2136
- func("introspect", Napi::Function::New(env, GetTypeDefinition));
2118
+ exports.Set("sizeof", Napi::Function::New(env, GetTypeSize));
2119
+ exports.Set("alignof", Napi::Function::New(env, GetTypeAlign));
2120
+ exports.Set("offsetof", Napi::Function::New(env, GetMemberOffset));
2121
+ exports.Set("resolve", Napi::Function::New(env, GetResolvedType));
2122
+ exports.Set("introspect", Napi::Function::New(env, GetTypeDefinition));
2137
2123
 
2138
- func("load", Napi::Function::New(env, LoadSharedLibrary));
2124
+ exports.Set("load", Napi::Function::New(env, LoadSharedLibrary));
2139
2125
 
2140
- func("in", Napi::Function::New(env, MarkIn));
2141
- func("out", Napi::Function::New(env, MarkOut));
2142
- func("inout", Napi::Function::New(env, MarkInOut));
2126
+ exports.Set("in", Napi::Function::New(env, MarkIn));
2127
+ exports.Set("out", Napi::Function::New(env, MarkOut));
2128
+ exports.Set("inout", Napi::Function::New(env, MarkInOut));
2143
2129
 
2144
- func("disposable", Napi::Function::New(env, CreateDisposableType));
2145
- func("free", Napi::Function::New(env, CallFree));
2130
+ exports.Set("disposable", Napi::Function::New(env, CreateDisposableType));
2131
+ exports.Set("free", Napi::Function::New(env, CallFree));
2146
2132
 
2147
- func("register", Napi::Function::New(env, RegisterCallback));
2148
- func("unregister", Napi::Function::New(env, UnregisterCallback));
2133
+ exports.Set("register", Napi::Function::New(env, RegisterCallback));
2134
+ exports.Set("unregister", Napi::Function::New(env, UnregisterCallback));
2149
2135
 
2150
- func("as", Napi::Function::New(env, CastValue));
2151
- func("decode", Napi::Function::New(env, DecodeValue));
2152
- func("address", Napi::Function::New(env, GetPointerAddress));
2153
- func("call", Napi::Function::New(env, CallPointerSync));
2136
+ exports.Set("as", Napi::Function::New(env, CastValue));
2137
+ exports.Set("decode", Napi::Function::New(env, DecodeValue));
2138
+ exports.Set("address", Napi::Function::New(env, GetPointerAddress));
2139
+ exports.Set("call", Napi::Function::New(env, CallPointerSync));
2154
2140
 
2155
- func("errno", Napi::Function::New(env, GetOrSetErrNo));
2141
+ exports.Set("errno", Napi::Function::New(env, GetOrSetErrNo));
2156
2142
 
2157
2143
  Napi::Object os = Napi::Object::New(env);
2158
- func("os", os);
2144
+ exports.Set("os", os);
2159
2145
 
2160
2146
  // Init constants mapping
2161
2147
  {
@@ -2169,85 +2155,47 @@ static void SetExports(Napi::Env env, Func func)
2169
2155
  }
2170
2156
 
2171
2157
  #if defined(_WIN32)
2172
- func("extension", Napi::String::New(env, ".dll"));
2158
+ exports.Set("extension", Napi::String::New(env, ".dll"));
2173
2159
  #elif defined(__APPLE__)
2174
- func("extension", Napi::String::New(env, ".dylib"));
2160
+ exports.Set("extension", Napi::String::New(env, ".dylib"));
2175
2161
  #else
2176
- func("extension", Napi::String::New(env, ".so"));
2162
+ exports.Set("extension", Napi::String::New(env, ".so"));
2177
2163
  #endif
2178
2164
 
2179
2165
  Napi::Object types = InitBaseTypes(env);
2180
- func("types", types);
2181
- }
2182
-
2183
- }
2184
-
2185
- #if NODE_WANT_INTERNALS
2166
+ exports.Set("types", types);
2186
2167
 
2187
- static void SetValue(node::Environment *env, v8::Local<v8::Object> target,
2188
- const char *name, Napi::Value value)
2189
- {
2190
- v8::Isolate *isolate = env->isolate();
2191
- v8::Local<v8::Context> context = isolate->GetCurrentContext();
2192
-
2193
- v8::NewStringType str_type = v8::NewStringType::kInternalized;
2194
- v8::Local<v8::String> str = v8::String::NewFromUtf8(isolate, name, str_type).ToLocalChecked();
2168
+ exports.Set("internal", Napi::Boolean::New(env, false));
2195
2169
 
2196
- target->Set(context, str, v8impl::V8LocalValueFromJsValue(value)).Check();
2170
+ return exports;
2197
2171
  }
2198
2172
 
2199
- static void InitInternal(v8::Local<v8::Object> target, v8::Local<v8::Value>,
2200
- v8::Local<v8::Context> context, void *)
2173
+ InstanceData::~InstanceData()
2201
2174
  {
2202
- using namespace RG;
2203
-
2204
- node::Environment *env = node::Environment::GetCurrent(context);
2205
-
2206
- // Not very clean but I don't know enough about Node and V8 to do better...
2207
- // ... and it seems to work okay.
2208
- napi_env env_napi = new napi_env__(context);
2209
- Napi::Env env_cxx(env_napi);
2210
- env->AtExit([](void *udata) {
2211
- napi_env env_napi = (napi_env)udata;
2212
- delete env_napi;
2213
- }, env_napi);
2175
+ for (InstanceMemory *mem: memories) {
2176
+ delete mem;
2177
+ }
2214
2178
 
2215
- InstanceData *instance = CreateInstance(env_cxx);
2216
- RG_CRITICAL(instance, "Failed to initialize Koffi");
2179
+ // Clean-up leftover trampoline references
2180
+ {
2181
+ std::lock_guard<std::mutex> lock(shared.mutex);
2217
2182
 
2218
- env_cxx.SetInstanceData(instance);
2183
+ for (int16_t idx = 0; idx < MaxTrampolines; idx++) {
2184
+ TrampolineInfo *trampoline = &shared.trampolines[idx];
2219
2185
 
2220
- instance->debug = GetDebugFlag("DUMP_CALLS");
2221
- FillRandomSafe(&instance->tag_lower, RG_SIZE(instance->tag_lower));
2186
+ if (trampoline->instance == this) {
2187
+ trampoline->instance = nullptr;
2188
+ trampoline->func.Reset();
2189
+ trampoline->recv.Reset();
2190
+ }
2191
+ }
2192
+ }
2222
2193
 
2223
- SetExports(env_napi, [&](const char *name, Napi::Value value) { SetValue(env, target, name, value); });
2224
- SetValue(env, target, "internal", Napi::Boolean::New(env_cxx, true));
2194
+ if (broker) {
2195
+ napi_release_threadsafe_function(broker, napi_tsfn_abort);
2196
+ }
2225
2197
  }
2226
2198
 
2227
- #else
2228
-
2229
- static Napi::Object InitModule(Napi::Env env, Napi::Object exports)
2230
- {
2231
- using namespace RG;
2232
-
2233
- InstanceData *instance = CreateInstance(env);
2234
- RG_CRITICAL(instance, "Failed to initialize Koffi");
2235
-
2236
- env.SetInstanceData(instance);
2237
-
2238
- instance->debug = GetDebugFlag("DUMP_CALLS");
2239
- FillRandomSafe(&instance->tag_lower, RG_SIZE(instance->tag_lower));
2240
-
2241
- SetExports(env, [&](const char *name, Napi::Value value) { exports.Set(name, value); });
2242
- exports.Set("internal", Napi::Boolean::New(env, false));
2199
+ NODE_API_MODULE(koffi, InitModule);
2243
2200
 
2244
- return exports;
2245
2201
  }
2246
-
2247
- #endif
2248
-
2249
- #if NODE_WANT_INTERNALS
2250
- NODE_MODULE_CONTEXT_AWARE_INTERNAL(koffi, InitInternal);
2251
- #else
2252
- NODE_API_MODULE(koffi, InitModule);
2253
- #endif