koffi 2.5.21-beta.2 → 2.5.21-beta.4
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/koffi/darwin_arm64/koffi.node +0 -0
- package/build/koffi/darwin_x64/koffi.node +0 -0
- package/build/koffi/freebsd_arm64/koffi.node +0 -0
- package/build/koffi/freebsd_ia32/koffi.node +0 -0
- package/build/koffi/freebsd_x64/koffi.node +0 -0
- package/build/koffi/linux_arm32hf/koffi.node +0 -0
- package/build/koffi/linux_arm64/koffi.node +0 -0
- package/build/koffi/linux_ia32/koffi.node +0 -0
- package/build/koffi/linux_riscv64hf64/koffi.node +0 -0
- package/build/koffi/linux_x64/koffi.node +0 -0
- package/build/koffi/openbsd_ia32/koffi.node +0 -0
- package/build/koffi/openbsd_x64/koffi.node +0 -0
- package/build/koffi/win32_arm64/koffi.node +0 -0
- package/build/koffi/win32_ia32/koffi.node +0 -0
- package/build/koffi/win32_x64/koffi.node +0 -0
- package/package.json +1 -1
- package/src/core/libcc/libcc.hh +8 -0
- package/src/index.d.ts +9 -1
- package/src/index.js +1 -1
- package/src/koffi/src/call.hh +2 -0
- package/src/koffi/src/ffi.cc +60 -4
- package/src/koffi/src/ffi.hh +3 -0
- package/src/koffi/src/util.cc +27 -17
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
package/src/core/libcc/libcc.hh
CHANGED
|
@@ -976,6 +976,8 @@ public:
|
|
|
976
976
|
void *Resize(void *ptr, Size old_size, Size new_size, unsigned int flags = 0) override;
|
|
977
977
|
void Release(const void *ptr, Size size) override;
|
|
978
978
|
|
|
979
|
+
bool IsUsed() const { return list.next; }
|
|
980
|
+
|
|
979
981
|
private:
|
|
980
982
|
static Bucket *PointerToBucket(void *ptr);
|
|
981
983
|
};
|
|
@@ -1002,6 +1004,12 @@ public:
|
|
|
1002
1004
|
void *Resize(void *ptr, Size old_size, Size new_size, unsigned int flags = 0) override;
|
|
1003
1005
|
void Release(const void *ptr, Size size) override;
|
|
1004
1006
|
|
|
1007
|
+
bool IsUsed() const
|
|
1008
|
+
{
|
|
1009
|
+
LinkedAllocator *alloc = ((BlockAllocatorBase *)this)->GetAllocator();
|
|
1010
|
+
return alloc->IsUsed();
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1005
1013
|
protected:
|
|
1006
1014
|
void CopyFrom(BlockAllocatorBase *other);
|
|
1007
1015
|
void ForgetCurrentBlock();
|
package/src/index.d.ts
CHANGED
|
@@ -28,7 +28,7 @@ declare module 'koffi' {
|
|
|
28
28
|
|
|
29
29
|
type PrimitiveKind = 'Void' | 'Bool' | 'Int8' | 'UInt8' | 'Int16' | 'Int16S' | 'UInt16' | 'UInt16S' |
|
|
30
30
|
'Int32' | 'Int32S' | 'UInt32' | 'UInt32S' | 'Int64' | 'Int64S' | 'UInt64' | 'UInt64S' |
|
|
31
|
-
'String' | 'String16' | 'Pointer' | 'Record'
|
|
31
|
+
'String' | 'String16' | 'Pointer' | 'Record' | 'Union' | 'Array' | 'Float32' | 'Float64' |
|
|
32
32
|
'Prototype' | 'Callback';
|
|
33
33
|
type ArrayHint = 'Array' | 'Typed' | 'String';
|
|
34
34
|
|
|
@@ -80,6 +80,8 @@ declare module 'koffi' {
|
|
|
80
80
|
thiscall(definition: string): KoffiFunction;
|
|
81
81
|
thiscall(name: string, result: TypeSpec, arguments: TypeSpec[]): KoffiFunction;
|
|
82
82
|
|
|
83
|
+
symbol(name: string, type: TypeSpec): any;
|
|
84
|
+
|
|
83
85
|
unload(): void;
|
|
84
86
|
}
|
|
85
87
|
|
|
@@ -129,6 +131,12 @@ declare module 'koffi' {
|
|
|
129
131
|
export function decode(value: any, offset: number, type: TypeSpec): any;
|
|
130
132
|
export function decode(value: any, offset: number, type: TypeSpec, len: number): any;
|
|
131
133
|
export function address(value: any): bigint;
|
|
134
|
+
export function encode(ref: any, type: TypeSpec): void;
|
|
135
|
+
export function encode(ref: any, type: TypeSpec, value: any): void;
|
|
136
|
+
export function encode(ref: any, type: TypeSpec, value: any, len: number): void;
|
|
137
|
+
export function encode(ref: any, offset: number, type: TypeSpec): void;
|
|
138
|
+
export function encode(ref: any, offset: number, type: TypeSpec, value: any): void;
|
|
139
|
+
export function encode(ref: any, offset: number, type: TypeSpec, value: any, len: number): void;
|
|
132
140
|
|
|
133
141
|
export function sizeof(type: TypeSpec): number;
|
|
134
142
|
export function alignof(type: TypeSpec): number;
|
package/src/index.js
CHANGED
|
@@ -378,7 +378,7 @@ var require_package = __commonJS({
|
|
|
378
378
|
"build/dist/src/koffi/package.json"(exports2, module2) {
|
|
379
379
|
module2.exports = {
|
|
380
380
|
name: "koffi",
|
|
381
|
-
version: "2.5.21-beta.
|
|
381
|
+
version: "2.5.21-beta.4",
|
|
382
382
|
stable: "2.5.20",
|
|
383
383
|
description: "Fast and simple C FFI (foreign function interface) for Node.js",
|
|
384
384
|
keywords: [
|
package/src/koffi/src/call.hh
CHANGED
package/src/koffi/src/ffi.cc
CHANGED
|
@@ -1558,6 +1558,43 @@ static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info, CallConve
|
|
|
1558
1558
|
return wrapper;
|
|
1559
1559
|
}
|
|
1560
1560
|
|
|
1561
|
+
static Napi::Value FindSymbol(const Napi::CallbackInfo &info)
|
|
1562
|
+
{
|
|
1563
|
+
Napi::Env env = info.Env();
|
|
1564
|
+
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
1565
|
+
LibraryHolder *lib = (LibraryHolder *)info.Data();
|
|
1566
|
+
|
|
1567
|
+
if (info.Length() < 2) {
|
|
1568
|
+
ThrowError<Napi::TypeError>(env, "Expected 2, got %1", info.Length());
|
|
1569
|
+
return env.Null();
|
|
1570
|
+
}
|
|
1571
|
+
if (!info[0].IsString()) {
|
|
1572
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
|
|
1573
|
+
return env.Null();
|
|
1574
|
+
}
|
|
1575
|
+
|
|
1576
|
+
std::string name = info[0].As<Napi::String>();
|
|
1577
|
+
|
|
1578
|
+
const TypeInfo *type = ResolveType(info[1]);
|
|
1579
|
+
if (!type)
|
|
1580
|
+
return env.Null();
|
|
1581
|
+
|
|
1582
|
+
#ifdef _WIN32
|
|
1583
|
+
void *ptr = (void *)GetProcAddress((HMODULE)lib->module, name.c_str());
|
|
1584
|
+
#else
|
|
1585
|
+
void *ptr = (void *)dlsym(lib->module, name.c_str());
|
|
1586
|
+
#endif
|
|
1587
|
+
if (!ptr) {
|
|
1588
|
+
ThrowError<Napi::Error>(env, "Cannot find symbol '%1' in shared library", name.c_str());
|
|
1589
|
+
return env.Null();
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
Napi::External<void> external = Napi::External<void>::New(env, ptr);
|
|
1593
|
+
SetValueTag(instance, external, &type);
|
|
1594
|
+
|
|
1595
|
+
return external;
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1561
1598
|
static Napi::Value UnloadLibrary(const Napi::CallbackInfo &info)
|
|
1562
1599
|
{
|
|
1563
1600
|
Napi::Env env = info.Env();
|
|
@@ -1607,6 +1644,18 @@ static Napi::Value LoadSharedLibrary(const Napi::CallbackInfo &info)
|
|
|
1607
1644
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for filename, expected string or null", GetValueType(instance, info[0]));
|
|
1608
1645
|
return env.Null();
|
|
1609
1646
|
}
|
|
1647
|
+
if (info.Length() >= 2 && !IsObject(info[1])) {
|
|
1648
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for options, expected object", GetValueType(instance, info[1]));
|
|
1649
|
+
return env.Null();
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1652
|
+
#ifndef _WIN32
|
|
1653
|
+
bool lazy = false;
|
|
1654
|
+
if (info.Length() >= 2) {
|
|
1655
|
+
Napi::Object options = info[1].As<Napi::Object>();
|
|
1656
|
+
lazy = options.Get("lazy").ToBoolean();
|
|
1657
|
+
}
|
|
1658
|
+
#endif
|
|
1610
1659
|
|
|
1611
1660
|
if (!instance->memories.len) {
|
|
1612
1661
|
AllocateMemory(instance, instance->config.sync_stack_size, instance->config.sync_heap_size);
|
|
@@ -1628,8 +1677,10 @@ static Napi::Value LoadSharedLibrary(const Napi::CallbackInfo &info)
|
|
|
1628
1677
|
}
|
|
1629
1678
|
#else
|
|
1630
1679
|
if (info[0].IsString()) {
|
|
1680
|
+
int flags = lazy ? RTLD_LAZY : RTLD_NOW;
|
|
1681
|
+
|
|
1631
1682
|
std::string filename = info[0].As<Napi::String>();
|
|
1632
|
-
module = dlopen(filename.c_str(),
|
|
1683
|
+
module = dlopen(filename.c_str(), flags);
|
|
1633
1684
|
|
|
1634
1685
|
if (!module) {
|
|
1635
1686
|
const char *msg = dlerror();
|
|
@@ -1654,13 +1705,14 @@ static Napi::Value LoadSharedLibrary(const Napi::CallbackInfo &info)
|
|
|
1654
1705
|
|
|
1655
1706
|
Napi::Object obj = Napi::Object::New(env);
|
|
1656
1707
|
|
|
1657
|
-
#define
|
|
1708
|
+
#define ADD_METHOD(Name, Call) \
|
|
1658
1709
|
do { \
|
|
1659
|
-
const auto wrapper = [](const Napi::CallbackInfo &info) { return
|
|
1710
|
+
const auto wrapper = [](const Napi::CallbackInfo &info) { return Call; }; \
|
|
1660
1711
|
Napi::Function func = Napi::Function::New(env, wrapper, (Name), (void *)lib->Ref()); \
|
|
1661
1712
|
func.AddFinalizer([](Napi::Env, LibraryHolder *lib) { lib->Unref(); }, lib); \
|
|
1662
1713
|
obj.Set((Name), func); \
|
|
1663
1714
|
} while (false)
|
|
1715
|
+
#define ADD_CONVENTION(Name, Value) ADD_METHOD((Name), FindLibraryFunction(info, Value))
|
|
1664
1716
|
|
|
1665
1717
|
ADD_CONVENTION("func", CallConvention::Cdecl);
|
|
1666
1718
|
ADD_CONVENTION("cdecl", CallConvention::Cdecl);
|
|
@@ -1668,10 +1720,14 @@ static Napi::Value LoadSharedLibrary(const Napi::CallbackInfo &info)
|
|
|
1668
1720
|
ADD_CONVENTION("fastcall", CallConvention::Fastcall);
|
|
1669
1721
|
ADD_CONVENTION("thiscall", CallConvention::Thiscall);
|
|
1670
1722
|
|
|
1671
|
-
|
|
1723
|
+
ADD_METHOD("symbol", FindSymbol(info));
|
|
1672
1724
|
|
|
1725
|
+
// We can't unref the library after unload, obviously
|
|
1673
1726
|
obj.Set("unload", Napi::Function::New(env, UnloadLibrary, "unload", (void *)lib->Ref()));
|
|
1674
1727
|
|
|
1728
|
+
#undef ADD_CONVENTION
|
|
1729
|
+
#undef ADD_METHOD
|
|
1730
|
+
|
|
1675
1731
|
return obj;
|
|
1676
1732
|
}
|
|
1677
1733
|
|
package/src/koffi/src/ffi.hh
CHANGED
package/src/koffi/src/util.cc
CHANGED
|
@@ -1230,7 +1230,6 @@ bool Encode(Napi::Value ref, Size offset, Napi::Value value, const TypeInfo *typ
|
|
|
1230
1230
|
bool Encode(Napi::Env env, uint8_t *origin, Napi::Value value, const TypeInfo *type, const Size *len)
|
|
1231
1231
|
{
|
|
1232
1232
|
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
1233
|
-
CallData *call = GetThreadCall();
|
|
1234
1233
|
|
|
1235
1234
|
if (len && type->primitive != PrimitiveKind::String &&
|
|
1236
1235
|
type->primitive != PrimitiveKind::String16 &&
|
|
@@ -1243,10 +1242,8 @@ bool Encode(Napi::Env env, uint8_t *origin, Napi::Value value, const TypeInfo *t
|
|
|
1243
1242
|
type = MakeArrayType(instance, type, *len);
|
|
1244
1243
|
}
|
|
1245
1244
|
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
return false;
|
|
1249
|
-
}
|
|
1245
|
+
InstanceMemory mem = {};
|
|
1246
|
+
CallData call(env, instance, &mem);
|
|
1250
1247
|
|
|
1251
1248
|
#define PUSH_INTEGER(CType) \
|
|
1252
1249
|
do { \
|
|
@@ -1297,19 +1294,19 @@ bool Encode(Napi::Env env, uint8_t *origin, Napi::Value value, const TypeInfo *t
|
|
|
1297
1294
|
case PrimitiveKind::UInt64S: { PUSH_INTEGER_SWAP(uint64_t); } break;
|
|
1298
1295
|
case PrimitiveKind::String: {
|
|
1299
1296
|
const char *str;
|
|
1300
|
-
if (!call
|
|
1297
|
+
if (!call.PushString(value, 1, &str)) [[unlikely]]
|
|
1301
1298
|
return false;
|
|
1302
1299
|
*(const char **)origin = str;
|
|
1303
1300
|
} break;
|
|
1304
1301
|
case PrimitiveKind::String16: {
|
|
1305
1302
|
const char16_t *str16;
|
|
1306
|
-
if (!call
|
|
1303
|
+
if (!call.PushString16(value, 1, &str16)) [[unlikely]]
|
|
1307
1304
|
return false;
|
|
1308
1305
|
*(const char16_t **)origin = str16;
|
|
1309
1306
|
} break;
|
|
1310
1307
|
case PrimitiveKind::Pointer: {
|
|
1311
1308
|
void *ptr;
|
|
1312
|
-
if (!call
|
|
1309
|
+
if (!call.PushPointer(value, type, 1, &ptr)) [[unlikely]]
|
|
1313
1310
|
return false;
|
|
1314
1311
|
*(void **)origin = ptr;
|
|
1315
1312
|
} break;
|
|
@@ -1322,7 +1319,7 @@ bool Encode(Napi::Env env, uint8_t *origin, Napi::Value value, const TypeInfo *t
|
|
|
1322
1319
|
|
|
1323
1320
|
Napi::Object obj = value.As<Napi::Object>();
|
|
1324
1321
|
|
|
1325
|
-
if (!call
|
|
1322
|
+
if (!call.PushObject(obj, type, origin))
|
|
1326
1323
|
return false;
|
|
1327
1324
|
} break;
|
|
1328
1325
|
case PrimitiveKind::Array: {
|
|
@@ -1330,15 +1327,15 @@ bool Encode(Napi::Env env, uint8_t *origin, Napi::Value value, const TypeInfo *t
|
|
|
1330
1327
|
Napi::Array array = value.As<Napi::Array>();
|
|
1331
1328
|
Size len = (Size)type->size / type->ref.type->size;
|
|
1332
1329
|
|
|
1333
|
-
if (!call
|
|
1330
|
+
if (!call.PushNormalArray(array, len, type, origin))
|
|
1334
1331
|
return false;
|
|
1335
1332
|
} else if (IsRawBuffer(value)) {
|
|
1336
1333
|
Span<const uint8_t> buffer = GetRawBuffer(value);
|
|
1337
1334
|
|
|
1338
|
-
if (!call
|
|
1335
|
+
if (!call.PushBuffer(buffer, type->size, type, origin))
|
|
1339
1336
|
return false;
|
|
1340
1337
|
} else if (value.IsString()) {
|
|
1341
|
-
if (!call
|
|
1338
|
+
if (!call.PushStringArray(value, type, origin))
|
|
1342
1339
|
return false;
|
|
1343
1340
|
} else {
|
|
1344
1341
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected array", GetValueType(instance, value));
|
|
@@ -1367,11 +1364,8 @@ bool Encode(Napi::Env env, uint8_t *origin, Napi::Value value, const TypeInfo *t
|
|
|
1367
1364
|
void *ptr;
|
|
1368
1365
|
|
|
1369
1366
|
if (value.IsFunction()) {
|
|
1370
|
-
Napi::
|
|
1371
|
-
|
|
1372
|
-
ptr = call->ReserveTrampoline(type->ref.proto, func);
|
|
1373
|
-
if (!ptr) [[unlikely]]
|
|
1374
|
-
return false;
|
|
1367
|
+
ThrowError<Napi::Error>(env, "Cannot encode non-registered callback");
|
|
1368
|
+
return false;
|
|
1375
1369
|
} else if (CheckValueTag(instance, value, type->ref.marker)) {
|
|
1376
1370
|
ptr = value.As<Napi::External<void>>().Data();
|
|
1377
1371
|
} else if (IsNullOrUndefined(value)) {
|
|
@@ -1390,6 +1384,22 @@ bool Encode(Napi::Env env, uint8_t *origin, Napi::Value value, const TypeInfo *t
|
|
|
1390
1384
|
#undef PUSH_INTEGER_SWAP
|
|
1391
1385
|
#undef PUSH_INTEGER
|
|
1392
1386
|
|
|
1387
|
+
// Keep memory around if any was allocated
|
|
1388
|
+
{
|
|
1389
|
+
BlockAllocator *alloc = call.GetAllocator();
|
|
1390
|
+
|
|
1391
|
+
if (alloc->IsUsed()) {
|
|
1392
|
+
BlockAllocator *copy = instance->encode_map.FindValue(origin, nullptr);
|
|
1393
|
+
|
|
1394
|
+
if (!copy) {
|
|
1395
|
+
copy = instance->encode_allocators.AppendDefault();
|
|
1396
|
+
instance->encode_map.Set(origin, copy);
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
std::swap(*alloc, *copy);
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1393
1403
|
return true;
|
|
1394
1404
|
}
|
|
1395
1405
|
|