koffi 2.4.2 → 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.
- package/build/2.5.0-beta.1/koffi_darwin_arm64/koffi.node +0 -0
- package/build/2.5.0-beta.1/koffi_darwin_x64/koffi.node +0 -0
- package/build/2.5.0-beta.1/koffi_freebsd_arm64/koffi.node +0 -0
- package/build/2.5.0-beta.1/koffi_freebsd_ia32/koffi.node +0 -0
- package/build/2.5.0-beta.1/koffi_freebsd_x64/koffi.node +0 -0
- package/build/2.5.0-beta.1/koffi_linux_arm32hf/koffi.node +0 -0
- package/build/2.5.0-beta.1/koffi_linux_arm64/koffi.node +0 -0
- package/build/2.5.0-beta.1/koffi_linux_ia32/koffi.node +0 -0
- package/build/2.5.0-beta.1/koffi_linux_riscv64hf64/koffi.node +0 -0
- package/build/2.5.0-beta.1/koffi_linux_x64/koffi.node +0 -0
- package/build/2.5.0-beta.1/koffi_openbsd_ia32/koffi.node +0 -0
- package/build/{2.4.2 → 2.5.0-beta.1}/koffi_openbsd_x64/koffi.node +0 -0
- package/build/2.5.0-beta.1/koffi_win32_arm64/koffi.node +0 -0
- package/build/{2.4.2 → 2.5.0-beta.1}/koffi_win32_ia32/koffi.node +0 -0
- package/build/{2.4.2 → 2.5.0-beta.1}/koffi_win32_x64/koffi.node +0 -0
- package/build/2.5.0-beta.1/koffi_win32_x64/koffi.pdb +0 -0
- package/doc/callbacks.md +1 -1
- package/doc/conf.py +1 -1
- package/doc/functions.md +1 -1
- package/doc/parameters.md +0 -1
- package/doc/pointers.md +1 -1
- package/package.json +1 -1
- package/src/core/libcc/libcc.cc +58 -54
- package/src/core/libcc/libcc.hh +33 -19
- package/src/koffi/src/abi_x86.cc +31 -4
- package/src/koffi/src/call.cc +37 -22
- package/src/koffi/src/ffi.cc +251 -303
- package/src/koffi/src/ffi.hh +3 -1
- package/src/koffi/src/util.cc +20 -13
- package/src/koffi/src/util.hh +4 -2
- package/build/2.4.2/koffi_darwin_arm64/koffi.node +0 -0
- package/build/2.4.2/koffi_darwin_x64/koffi.node +0 -0
- package/build/2.4.2/koffi_freebsd_arm64/koffi.node +0 -0
- package/build/2.4.2/koffi_freebsd_ia32/koffi.node +0 -0
- package/build/2.4.2/koffi_freebsd_x64/koffi.node +0 -0
- package/build/2.4.2/koffi_linux_arm32hf/koffi.node +0 -0
- package/build/2.4.2/koffi_linux_arm64/koffi.node +0 -0
- package/build/2.4.2/koffi_linux_ia32/koffi.node +0 -0
- package/build/2.4.2/koffi_linux_riscv64hf64/koffi.node +0 -0
- package/build/2.4.2/koffi_linux_x64/koffi.node +0 -0
- package/build/2.4.2/koffi_openbsd_ia32/koffi.node +0 -0
- package/build/2.4.2/koffi_win32_arm64/koffi.node +0 -0
- /package/build/{2.4.2 → 2.5.0-beta.1}/koffi_win32_arm64/koffi.exp +0 -0
- /package/build/{2.4.2 → 2.5.0-beta.1}/koffi_win32_arm64/koffi.lib +0 -0
- /package/build/{2.4.2 → 2.5.0-beta.1}/koffi_win32_ia32/koffi.exp +0 -0
- /package/build/{2.4.2 → 2.5.0-beta.1}/koffi_win32_ia32/koffi.lib +0 -0
- /package/build/{2.4.2 → 2.5.0-beta.1}/koffi_win32_x64/koffi.exp +0 -0
- /package/build/{2.4.2 → 2.5.0-beta.1}/koffi_win32_x64/koffi.lib +0 -0
package/src/koffi/src/ffi.cc
CHANGED
|
@@ -993,12 +993,15 @@ static Napi::Value CreateTypeAlias(const Napi::CallbackInfo &info)
|
|
|
993
993
|
if (!type)
|
|
994
994
|
return env.Null();
|
|
995
995
|
|
|
996
|
-
|
|
997
|
-
|
|
996
|
+
// Alias the type
|
|
997
|
+
{
|
|
998
|
+
bool inserted;
|
|
999
|
+
instance->types_map.TrySet(alias, type, &inserted);
|
|
998
1000
|
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2090
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2117
|
-
|
|
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
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
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
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
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
|
-
|
|
2124
|
+
exports.Set("load", Napi::Function::New(env, LoadSharedLibrary));
|
|
2139
2125
|
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
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
|
-
|
|
2145
|
-
|
|
2130
|
+
exports.Set("disposable", Napi::Function::New(env, CreateDisposableType));
|
|
2131
|
+
exports.Set("free", Napi::Function::New(env, CallFree));
|
|
2146
2132
|
|
|
2147
|
-
|
|
2148
|
-
|
|
2133
|
+
exports.Set("register", Napi::Function::New(env, RegisterCallback));
|
|
2134
|
+
exports.Set("unregister", Napi::Function::New(env, UnregisterCallback));
|
|
2149
2135
|
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
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
|
-
|
|
2141
|
+
exports.Set("errno", Napi::Function::New(env, GetOrSetErrNo));
|
|
2156
2142
|
|
|
2157
2143
|
Napi::Object os = Napi::Object::New(env);
|
|
2158
|
-
|
|
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
|
-
|
|
2158
|
+
exports.Set("extension", Napi::String::New(env, ".dll"));
|
|
2173
2159
|
#elif defined(__APPLE__)
|
|
2174
|
-
|
|
2160
|
+
exports.Set("extension", Napi::String::New(env, ".dylib"));
|
|
2175
2161
|
#else
|
|
2176
|
-
|
|
2162
|
+
exports.Set("extension", Napi::String::New(env, ".so"));
|
|
2177
2163
|
#endif
|
|
2178
2164
|
|
|
2179
2165
|
Napi::Object types = InitBaseTypes(env);
|
|
2180
|
-
|
|
2181
|
-
}
|
|
2182
|
-
|
|
2183
|
-
}
|
|
2184
|
-
|
|
2185
|
-
#if NODE_WANT_INTERNALS
|
|
2166
|
+
exports.Set("types", types);
|
|
2186
2167
|
|
|
2187
|
-
|
|
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
|
-
|
|
2170
|
+
return exports;
|
|
2197
2171
|
}
|
|
2198
2172
|
|
|
2199
|
-
|
|
2200
|
-
v8::Local<v8::Context> context, void *)
|
|
2173
|
+
InstanceData::~InstanceData()
|
|
2201
2174
|
{
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
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
|
-
|
|
2216
|
-
|
|
2179
|
+
// Clean-up leftover trampoline references
|
|
2180
|
+
{
|
|
2181
|
+
std::lock_guard<std::mutex> lock(shared.mutex);
|
|
2217
2182
|
|
|
2218
|
-
|
|
2183
|
+
for (int16_t idx = 0; idx < MaxTrampolines; idx++) {
|
|
2184
|
+
TrampolineInfo *trampoline = &shared.trampolines[idx];
|
|
2219
2185
|
|
|
2220
|
-
|
|
2221
|
-
|
|
2186
|
+
if (trampoline->instance == this) {
|
|
2187
|
+
trampoline->instance = nullptr;
|
|
2188
|
+
trampoline->func.Reset();
|
|
2189
|
+
trampoline->recv.Reset();
|
|
2190
|
+
}
|
|
2191
|
+
}
|
|
2192
|
+
}
|
|
2222
2193
|
|
|
2223
|
-
|
|
2224
|
-
|
|
2194
|
+
if (broker) {
|
|
2195
|
+
napi_release_threadsafe_function(broker, napi_tsfn_abort);
|
|
2196
|
+
}
|
|
2225
2197
|
}
|
|
2226
2198
|
|
|
2227
|
-
|
|
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
|
package/src/koffi/src/ffi.hh
CHANGED
|
@@ -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
|
-
|
|
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;
|