koffi 2.4.1 → 2.5.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 (50) hide show
  1. package/CHANGELOG.md +12 -2
  2. package/build/2.5.0-beta.1/koffi_darwin_arm64/koffi.node +0 -0
  3. package/build/2.5.0-beta.1/koffi_darwin_x64/koffi.node +0 -0
  4. package/build/2.5.0-beta.1/koffi_freebsd_arm64/koffi.node +0 -0
  5. package/build/2.5.0-beta.1/koffi_freebsd_ia32/koffi.node +0 -0
  6. package/build/2.5.0-beta.1/koffi_freebsd_x64/koffi.node +0 -0
  7. package/build/2.5.0-beta.1/koffi_linux_arm32hf/koffi.node +0 -0
  8. package/build/2.5.0-beta.1/koffi_linux_arm64/koffi.node +0 -0
  9. package/build/2.5.0-beta.1/koffi_linux_ia32/koffi.node +0 -0
  10. package/build/2.5.0-beta.1/koffi_linux_riscv64hf64/koffi.node +0 -0
  11. package/build/2.5.0-beta.1/koffi_linux_x64/koffi.node +0 -0
  12. package/build/2.5.0-beta.1/koffi_openbsd_ia32/koffi.node +0 -0
  13. package/build/{2.4.1 → 2.5.0-beta.1}/koffi_openbsd_x64/koffi.node +0 -0
  14. package/build/2.5.0-beta.1/koffi_win32_arm64/koffi.node +0 -0
  15. package/build/{2.4.1 → 2.5.0-beta.1}/koffi_win32_ia32/koffi.node +0 -0
  16. package/build/{2.4.1 → 2.5.0-beta.1}/koffi_win32_x64/koffi.node +0 -0
  17. package/build/2.5.0-beta.1/koffi_win32_x64/koffi.pdb +0 -0
  18. package/doc/callbacks.md +1 -1
  19. package/doc/conf.py +1 -1
  20. package/doc/functions.md +73 -4
  21. package/doc/parameters.md +0 -1
  22. package/doc/pointers.md +1 -1
  23. package/package.json +2 -2
  24. package/src/core/libcc/libcc.cc +58 -54
  25. package/src/core/libcc/libcc.hh +33 -19
  26. package/src/koffi/src/abi_x86.cc +31 -4
  27. package/src/koffi/src/call.cc +37 -22
  28. package/src/koffi/src/ffi.cc +253 -310
  29. package/src/koffi/src/ffi.hh +3 -1
  30. package/src/koffi/src/parser.cc +1 -1
  31. package/src/koffi/src/util.cc +24 -13
  32. package/src/koffi/src/util.hh +4 -2
  33. package/build/2.4.1/koffi_darwin_arm64/koffi.node +0 -0
  34. package/build/2.4.1/koffi_darwin_x64/koffi.node +0 -0
  35. package/build/2.4.1/koffi_freebsd_arm64/koffi.node +0 -0
  36. package/build/2.4.1/koffi_freebsd_ia32/koffi.node +0 -0
  37. package/build/2.4.1/koffi_freebsd_x64/koffi.node +0 -0
  38. package/build/2.4.1/koffi_linux_arm32hf/koffi.node +0 -0
  39. package/build/2.4.1/koffi_linux_arm64/koffi.node +0 -0
  40. package/build/2.4.1/koffi_linux_ia32/koffi.node +0 -0
  41. package/build/2.4.1/koffi_linux_riscv64hf64/koffi.node +0 -0
  42. package/build/2.4.1/koffi_linux_x64/koffi.node +0 -0
  43. package/build/2.4.1/koffi_openbsd_ia32/koffi.node +0 -0
  44. package/build/2.4.1/koffi_win32_arm64/koffi.node +0 -0
  45. /package/build/{2.4.1 → 2.5.0-beta.1}/koffi_win32_arm64/koffi.exp +0 -0
  46. /package/build/{2.4.1 → 2.5.0-beta.1}/koffi_win32_arm64/koffi.lib +0 -0
  47. /package/build/{2.4.1 → 2.5.0-beta.1}/koffi_win32_ia32/koffi.exp +0 -0
  48. /package/build/{2.4.1 → 2.5.0-beta.1}/koffi_win32_ia32/koffi.lib +0 -0
  49. /package/build/{2.4.1 → 2.5.0-beta.1}/koffi_win32_x64/koffi.exp +0 -0
  50. /package/build/{2.4.1 → 2.5.0-beta.1}/koffi_win32_x64/koffi.lib +0 -0
@@ -895,7 +895,7 @@ static bool ParseClassicFunction(Napi::Env env, Napi::String name, Napi::Value r
895
895
  if (!param.type)
896
896
  return false;
897
897
  if (!CanPassType(param.type, param.directions)) {
898
- ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter (maybe try %1 *)", param.type->name);
898
+ ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter", param.type->name);
899
899
  return false;
900
900
  }
901
901
  if (func->parameters.len >= MaxParameters) {
@@ -942,11 +942,6 @@ static Napi::Value CreateFunctionType(const Napi::CallbackInfo &info)
942
942
  return env.Null();
943
943
  }
944
944
 
945
- if (func->variadic) {
946
- LogError("Variadic callbacks are not supported");
947
- return env.Null();
948
- }
949
-
950
945
  if (!AnalyseFunction(env, instance, func))
951
946
  return env.Null();
952
947
 
@@ -998,12 +993,15 @@ static Napi::Value CreateTypeAlias(const Napi::CallbackInfo &info)
998
993
  if (!type)
999
994
  return env.Null();
1000
995
 
1001
- bool inserted;
1002
- instance->types_map.TrySet(alias, type, &inserted);
996
+ // Alias the type
997
+ {
998
+ bool inserted;
999
+ instance->types_map.TrySet(alias, type, &inserted);
1003
1000
 
1004
- if (!inserted) {
1005
- ThrowError<Napi::Error>(env, "Type name '%1' already exists", alias);
1006
- return env.Null();
1001
+ if (!inserted) {
1002
+ ThrowError<Napi::Error>(env, "Type name '%1' already exists", alias);
1003
+ return env.Null();
1004
+ }
1007
1005
  }
1008
1006
 
1009
1007
  return WrapType(env, instance, type);
@@ -1310,7 +1308,7 @@ static Napi::Value TranslateVariadicCall(const FunctionInfo *func, void *native,
1310
1308
  if (RG_UNLIKELY(!param.type))
1311
1309
  return env.Null();
1312
1310
  if (RG_UNLIKELY(!CanPassType(param.type, param.directions))) {
1313
- ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter (maybe try %1 *)", param.type->name);
1311
+ ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter", param.type->name);
1314
1312
  return env.Null();
1315
1313
  }
1316
1314
  if (RG_UNLIKELY(copy.parameters.len >= MaxParameters)) {
@@ -1456,6 +1454,35 @@ Napi::Value TranslateAsyncCall(const Napi::CallbackInfo &info)
1456
1454
  return TranslateAsyncCall(func, func->native, info);
1457
1455
  }
1458
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
+
1459
1486
  static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info, CallConvention convention)
1460
1487
  {
1461
1488
  Napi::Env env = info.Env();
@@ -1730,6 +1757,116 @@ static Napi::Value UnregisterCallback(const Napi::CallbackInfo &info)
1730
1757
  return env.Undefined();
1731
1758
  }
1732
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
+
1733
1870
  void LibraryHolder::Unload()
1734
1871
  {
1735
1872
  #ifdef _WIN32
@@ -1758,6 +1895,45 @@ void LibraryHolder::Unref() const
1758
1895
  }
1759
1896
  }
1760
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
+
1761
1937
  static void RegisterPrimitiveType(Napi::Env env, Napi::Object map, std::initializer_list<const char *> names,
1762
1938
  PrimitiveKind primitive, int32_t size, int16_t align, const char *ref = nullptr)
1763
1939
  {
@@ -1882,50 +2058,13 @@ static Napi::Object InitBaseTypes(Napi::Env env)
1882
2058
  instance->char_type = instance->types_map.FindValue("char", nullptr);
1883
2059
  instance->char16_type = instance->types_map.FindValue("char16", nullptr);
1884
2060
 
2061
+ instance->active_symbol = Napi::Symbol::New(env, "active");
2062
+
1885
2063
  types.Freeze();
1886
2064
 
1887
2065
  return types;
1888
2066
  }
1889
2067
 
1890
- FunctionInfo::~FunctionInfo()
1891
- {
1892
- if (lib) {
1893
- lib->Unref();
1894
- }
1895
- }
1896
-
1897
- const FunctionInfo *FunctionInfo::Ref() const
1898
- {
1899
- refcount++;
1900
- return this;
1901
- }
1902
-
1903
- void FunctionInfo::Unref() const
1904
- {
1905
- if (!--refcount) {
1906
- delete this;
1907
- }
1908
- }
1909
-
1910
- InstanceMemory::~InstanceMemory()
1911
- {
1912
- #ifdef _WIN32
1913
- if (stack.ptr) {
1914
- VirtualFree(stack.ptr, 0, MEM_RELEASE);
1915
- }
1916
- if (heap.ptr) {
1917
- VirtualFree(heap.ptr, 0, MEM_RELEASE);
1918
- }
1919
- #else
1920
- if (stack.ptr) {
1921
- munmap(stack.ptr, stack.len);
1922
- }
1923
- if (heap.ptr) {
1924
- munmap(heap.ptr, heap.len);
1925
- }
1926
- #endif
1927
- }
1928
-
1929
2068
  static InstanceData *CreateInstance(Napi::Env env)
1930
2069
  {
1931
2070
  InstanceData *instance = new InstanceData();
@@ -1933,6 +2072,9 @@ static InstanceData *CreateInstance(Napi::Env env)
1933
2072
 
1934
2073
  instance->main_thread_id = std::this_thread::get_id();
1935
2074
 
2075
+ instance->debug = GetDebugFlag("DUMP_CALLS");
2076
+ FillRandomSafe(&instance->tag_lower, RG_SIZE(instance->tag_lower));
2077
+
1936
2078
  if (napi_create_threadsafe_function(env, nullptr, nullptr,
1937
2079
  Napi::String::New(env, "Koffi Async Callback Broker"),
1938
2080
  0, 1, nullptr, nullptr, nullptr,
@@ -1953,214 +2095,53 @@ static InstanceData *CreateInstance(Napi::Env env)
1953
2095
  return instance;
1954
2096
  }
1955
2097
 
1956
- InstanceData::~InstanceData()
1957
- {
1958
- for (InstanceMemory *mem: memories) {
1959
- delete mem;
1960
- }
1961
-
1962
- // Clean-up leftover trampoline references
1963
- {
1964
- std::lock_guard<std::mutex> lock(shared.mutex);
1965
-
1966
- for (int16_t idx = 0; idx < MaxTrampolines; idx++) {
1967
- TrampolineInfo *trampoline = &shared.trampolines[idx];
1968
-
1969
- if (trampoline->instance == this) {
1970
- trampoline->instance = nullptr;
1971
- trampoline->func.Reset();
1972
- trampoline->recv.Reset();
1973
- }
1974
- }
1975
- }
1976
-
1977
- if (broker) {
1978
- napi_release_threadsafe_function(broker, napi_tsfn_abort);
1979
- }
1980
- }
1981
-
1982
- static Napi::Value CastValue(const Napi::CallbackInfo &info)
1983
- {
1984
- Napi::Env env = info.Env();
1985
- InstanceData *instance = env.GetInstanceData<InstanceData>();
1986
-
1987
- if (RG_UNLIKELY(info.Length() < 2)) {
1988
- ThrowError<Napi::TypeError>(env, "Expected 2 arguments, got %1", info.Length());
1989
- return env.Null();
1990
- }
1991
-
1992
- Napi::Value value = info[0];
1993
-
1994
- const TypeInfo *type = ResolveType(info[1]);
1995
- if (RG_UNLIKELY(!type))
1996
- return env.Null();
1997
- if (type->primitive != PrimitiveKind::Pointer &&
1998
- type->primitive != PrimitiveKind::String &&
1999
- type->primitive != PrimitiveKind::String16) {
2000
- ThrowError<Napi::TypeError>(env, "Only pointer or string types can be used for casting");
2001
- return env.Null();
2002
- }
2003
-
2004
- ValueCast *cast = new ValueCast;
2005
-
2006
- cast->ref.Reset(value, 1);
2007
- cast->type = type;
2008
-
2009
- Napi::External<ValueCast> external = Napi::External<ValueCast>::New(env, cast, [](Napi::Env, ValueCast *cast) { delete cast; });
2010
- SetValueTag(instance, external, &CastMarker);
2011
-
2012
- return external;
2013
- }
2014
-
2015
- static Napi::Value DecodeValue(const Napi::CallbackInfo &info)
2016
- {
2017
- Napi::Env env = info.Env();
2018
-
2019
- bool has_offset = (info.Length() >= 2 && info[1].IsNumber());
2020
- bool has_len = (info.Length() >= 3u + has_offset && info[2u + has_offset].IsNumber());
2021
-
2022
- if (RG_UNLIKELY(info.Length() < 2u + has_offset)) {
2023
- ThrowError<Napi::TypeError>(env, "Expected %1 to 4 arguments, got %2", 2 + has_offset, info.Length());
2024
- return env.Null();
2025
- }
2026
-
2027
- const TypeInfo *type = ResolveType(info[1u + has_offset]);
2028
- if (RG_UNLIKELY(!type))
2029
- return env.Null();
2030
-
2031
- Napi::Value value = info[0];
2032
- int64_t offset = has_offset ? info[1].As<Napi::Number>().Int64Value() : 0;
2033
-
2034
- if (has_len) {
2035
- Size len = info[2u + has_offset].As<Napi::Number>();
2036
-
2037
- Napi::Value ret = Decode(value, offset, type, &len);
2038
- return ret;
2039
- } else {
2040
- Napi::Value ret = Decode(value, offset, type);
2041
- return ret;
2042
- }
2043
- }
2044
-
2045
- static Napi::Value GetPointerAddress(const Napi::CallbackInfo &info)
2046
- {
2047
- Napi::Env env = info.Env();
2048
-
2049
- if (info.Length() < 1) {
2050
- ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
2051
- return env.Null();
2052
- }
2053
-
2054
- void *ptr = nullptr;
2055
- if (!GetExternalPointer(env, info[0], &ptr))
2056
- return env.Null();
2057
-
2058
- uint64_t ptr64 = (uint64_t)(uintptr_t)ptr;
2059
- Napi::BigInt bigint = Napi::BigInt::New(env, ptr64);
2060
-
2061
- return bigint;
2062
- }
2063
-
2064
- static Napi::Value CallPointerSync(const Napi::CallbackInfo &info)
2065
- {
2066
- Napi::Env env = info.Env();
2067
- InstanceData *instance = env.GetInstanceData<InstanceData>();
2068
-
2069
- if (RG_UNLIKELY(info.Length() < 2)) {
2070
- ThrowError<Napi::TypeError>(env, "Expected 2 or more arguments, got %1", info.Length());
2071
- return env.Null();
2072
- }
2073
-
2074
- void *ptr = nullptr;
2075
- if (RG_UNLIKELY(!GetExternalPointer(env, info[0], &ptr)))
2076
- return env.Null();
2077
-
2078
- const TypeInfo *type = ResolveType(info[1]);
2079
- if (RG_UNLIKELY(!type))
2080
- return env.Null();
2081
- if (RG_UNLIKELY(type->primitive != PrimitiveKind::Prototype)) {
2082
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for type, expected function type", GetValueType(instance, info[1]));
2083
- return env.Null();
2084
- }
2085
-
2086
- const FunctionInfo *proto = type->ref.proto;
2087
- RG_ASSERT(!proto->variadic);
2088
-
2089
- return TranslateNormalCall(proto, ptr, info);
2090
- }
2091
-
2092
- 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)
2093
2099
  {
2094
- if (RG_LIKELY(exec_call)) {
2095
- exec_call->RelaySafe(idx, own_sp, caller_sp, false, out_reg);
2096
- } else {
2097
- // This happens if the callback pointer is called from a different thread
2098
- // than the one that runs the FFI call (sync or async).
2099
-
2100
- TrampolineInfo *trampoline = &shared.trampolines[idx];
2101
-
2102
- Napi::Env env = trampoline->func.Env();
2103
- InstanceData *instance = env.GetInstanceData<InstanceData>();
2104
-
2105
- InstanceMemory *mem = AllocateMemory(instance, instance->config.async_stack_size, instance->config.async_heap_size);
2106
- if (RG_UNLIKELY(!mem)) {
2107
- ThrowError<Napi::Error>(env, "Too many asynchronous calls are running");
2108
- return;
2109
- }
2110
-
2111
- // Avoid triggering the "use callback beyond FFI" check
2112
- RG_DEFER_C(generation = trampoline->generation) { trampoline->generation = generation; };
2113
- trampoline->generation = -1;
2100
+ InstanceData *instance = CreateInstance(env);
2101
+ RG_CRITICAL(instance, "Failed to initialize Koffi");
2114
2102
 
2115
- // We set dispose_call to true so that the main thread will dispose of CallData itself
2116
- CallData call(env, instance, mem);
2117
- call.RelaySafe(idx, own_sp, caller_sp, true, out_reg);
2118
- }
2119
- }
2103
+ env.SetInstanceData(instance);
2120
2104
 
2121
- template <typename Func>
2122
- static void SetExports(Napi::Env env, Func func)
2123
- {
2124
- func("config", Napi::Function::New(env, GetSetConfig));
2125
- 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));
2126
2107
 
2127
- func("struct", Napi::Function::New(env, CreatePaddedStructType));
2128
- func("pack", Napi::Function::New(env, CreatePackedStructType));
2129
- // func("union", Napi::Function::New(env, CreateUnionType));
2130
- // func("Union", Napi::Function::New(env, InstantiateUnion));
2131
- func("opaque", Napi::Function::New(env, CreateOpaqueType));
2132
- func("pointer", Napi::Function::New(env, CreatePointerType));
2133
- func("array", Napi::Function::New(env, CreateArrayType));
2134
- func("proto", Napi::Function::New(env, CreateFunctionType));
2135
- 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));
2136
2117
 
2137
- func("sizeof", Napi::Function::New(env, GetTypeSize));
2138
- func("alignof", Napi::Function::New(env, GetTypeAlign));
2139
- func("offsetof", Napi::Function::New(env, GetMemberOffset));
2140
- func("resolve", Napi::Function::New(env, GetResolvedType));
2141
- 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));
2142
2123
 
2143
- func("load", Napi::Function::New(env, LoadSharedLibrary));
2124
+ exports.Set("load", Napi::Function::New(env, LoadSharedLibrary));
2144
2125
 
2145
- func("in", Napi::Function::New(env, MarkIn));
2146
- func("out", Napi::Function::New(env, MarkOut));
2147
- 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));
2148
2129
 
2149
- func("disposable", Napi::Function::New(env, CreateDisposableType));
2150
- 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));
2151
2132
 
2152
- func("register", Napi::Function::New(env, RegisterCallback));
2153
- 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));
2154
2135
 
2155
- func("as", Napi::Function::New(env, CastValue));
2156
- func("decode", Napi::Function::New(env, DecodeValue));
2157
- func("address", Napi::Function::New(env, GetPointerAddress));
2158
- 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));
2159
2140
 
2160
- func("errno", Napi::Function::New(env, GetOrSetErrNo));
2141
+ exports.Set("errno", Napi::Function::New(env, GetOrSetErrNo));
2161
2142
 
2162
2143
  Napi::Object os = Napi::Object::New(env);
2163
- func("os", os);
2144
+ exports.Set("os", os);
2164
2145
 
2165
2146
  // Init constants mapping
2166
2147
  {
@@ -2174,85 +2155,47 @@ static void SetExports(Napi::Env env, Func func)
2174
2155
  }
2175
2156
 
2176
2157
  #if defined(_WIN32)
2177
- func("extension", Napi::String::New(env, ".dll"));
2158
+ exports.Set("extension", Napi::String::New(env, ".dll"));
2178
2159
  #elif defined(__APPLE__)
2179
- func("extension", Napi::String::New(env, ".dylib"));
2160
+ exports.Set("extension", Napi::String::New(env, ".dylib"));
2180
2161
  #else
2181
- func("extension", Napi::String::New(env, ".so"));
2162
+ exports.Set("extension", Napi::String::New(env, ".so"));
2182
2163
  #endif
2183
2164
 
2184
2165
  Napi::Object types = InitBaseTypes(env);
2185
- func("types", types);
2186
- }
2187
-
2188
- }
2189
-
2190
- #if NODE_WANT_INTERNALS
2166
+ exports.Set("types", types);
2191
2167
 
2192
- static void SetValue(node::Environment *env, v8::Local<v8::Object> target,
2193
- const char *name, Napi::Value value)
2194
- {
2195
- v8::Isolate *isolate = env->isolate();
2196
- v8::Local<v8::Context> context = isolate->GetCurrentContext();
2197
-
2198
- v8::NewStringType str_type = v8::NewStringType::kInternalized;
2199
- v8::Local<v8::String> str = v8::String::NewFromUtf8(isolate, name, str_type).ToLocalChecked();
2168
+ exports.Set("internal", Napi::Boolean::New(env, false));
2200
2169
 
2201
- target->Set(context, str, v8impl::V8LocalValueFromJsValue(value)).Check();
2170
+ return exports;
2202
2171
  }
2203
2172
 
2204
- static void InitInternal(v8::Local<v8::Object> target, v8::Local<v8::Value>,
2205
- v8::Local<v8::Context> context, void *)
2173
+ InstanceData::~InstanceData()
2206
2174
  {
2207
- using namespace RG;
2208
-
2209
- node::Environment *env = node::Environment::GetCurrent(context);
2210
-
2211
- // Not very clean but I don't know enough about Node and V8 to do better...
2212
- // ... and it seems to work okay.
2213
- napi_env env_napi = new napi_env__(context);
2214
- Napi::Env env_cxx(env_napi);
2215
- env->AtExit([](void *udata) {
2216
- napi_env env_napi = (napi_env)udata;
2217
- delete env_napi;
2218
- }, env_napi);
2175
+ for (InstanceMemory *mem: memories) {
2176
+ delete mem;
2177
+ }
2219
2178
 
2220
- InstanceData *instance = CreateInstance(env_cxx);
2221
- RG_CRITICAL(instance, "Failed to initialize Koffi");
2179
+ // Clean-up leftover trampoline references
2180
+ {
2181
+ std::lock_guard<std::mutex> lock(shared.mutex);
2222
2182
 
2223
- env_cxx.SetInstanceData(instance);
2183
+ for (int16_t idx = 0; idx < MaxTrampolines; idx++) {
2184
+ TrampolineInfo *trampoline = &shared.trampolines[idx];
2224
2185
 
2225
- instance->debug = GetDebugFlag("DUMP_CALLS");
2226
- 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
+ }
2227
2193
 
2228
- SetExports(env_napi, [&](const char *name, Napi::Value value) { SetValue(env, target, name, value); });
2229
- SetValue(env, target, "internal", Napi::Boolean::New(env_cxx, true));
2194
+ if (broker) {
2195
+ napi_release_threadsafe_function(broker, napi_tsfn_abort);
2196
+ }
2230
2197
  }
2231
2198
 
2232
- #else
2233
-
2234
- static Napi::Object InitModule(Napi::Env env, Napi::Object exports)
2235
- {
2236
- using namespace RG;
2237
-
2238
- InstanceData *instance = CreateInstance(env);
2239
- RG_CRITICAL(instance, "Failed to initialize Koffi");
2240
-
2241
- env.SetInstanceData(instance);
2242
-
2243
- instance->debug = GetDebugFlag("DUMP_CALLS");
2244
- FillRandomSafe(&instance->tag_lower, RG_SIZE(instance->tag_lower));
2245
-
2246
- SetExports(env, [&](const char *name, Napi::Value value) { exports.Set(name, value); });
2247
- exports.Set("internal", Napi::Boolean::New(env, false));
2199
+ NODE_API_MODULE(koffi, InitModule);
2248
2200
 
2249
- return exports;
2250
2201
  }
2251
-
2252
- #endif
2253
-
2254
- #if NODE_WANT_INTERNALS
2255
- NODE_MODULE_CONTEXT_AWARE_INTERNAL(koffi, InitInternal);
2256
- #else
2257
- NODE_API_MODULE(koffi, InitModule);
2258
- #endif
@@ -198,7 +198,7 @@ struct ParameterInfo {
198
198
  int8_t vec_bytes; // ARM64
199
199
  #elif defined(__i386__) || defined(_M_IX86)
200
200
  bool trivial; // Only matters for return value
201
- bool fast;
201
+ int8_t fast;
202
202
  #elif __riscv_xlen == 64
203
203
  bool use_memory;
204
204
  int8_t gpr_count;
@@ -273,6 +273,8 @@ struct InstanceData {
273
273
  const TypeInfo *char_type;
274
274
  const TypeInfo *char16_type;
275
275
 
276
+ Napi::Symbol active_symbol;
277
+
276
278
  std::mutex memories_mutex;
277
279
  LocalArray<InstanceMemory *, 9> memories;
278
280
  int temporaries = 0;