koffi 2.0.1 → 2.1.0-beta.3
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/CMakeLists.txt +2 -9
- package/ChangeLog.md +17 -0
- package/benchmark/atoi_koffi.js +12 -8
- package/benchmark/atoi_napi.js +12 -8
- package/benchmark/atoi_node_ffi.js +11 -10
- package/benchmark/raylib_cc.cc +12 -9
- package/benchmark/raylib_koffi.js +15 -13
- package/benchmark/raylib_node_ffi.js +15 -13
- package/benchmark/raylib_node_raylib.js +14 -11
- package/build/qemu/2.1.0-beta.3/koffi_darwin_arm64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.3/koffi_darwin_x64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.3/koffi_freebsd_arm64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.3/koffi_freebsd_ia32.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.3/koffi_freebsd_x64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.3/koffi_linux_arm32hf.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.3/koffi_linux_arm64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.3/koffi_linux_ia32.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.3/koffi_linux_riscv64hf64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.3/koffi_linux_x64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.3/koffi_openbsd_ia32.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.3/koffi_openbsd_x64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.3/koffi_win32_arm64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.3/koffi_win32_ia32.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.3/koffi_win32_x64.tar.gz +0 -0
- package/doc/Makefile +1 -1
- package/doc/changes.md +12 -8
- package/doc/conf.py +5 -0
- package/doc/dist/doctrees/changes.doctree +0 -0
- package/doc/dist/doctrees/environment.pickle +0 -0
- package/doc/dist/doctrees/functions.doctree +0 -0
- package/doc/dist/doctrees/index.doctree +0 -0
- package/doc/dist/doctrees/types.doctree +0 -0
- package/doc/dist/html/.buildinfo +1 -1
- package/doc/dist/html/_sources/changes.md.txt +12 -8
- package/doc/dist/html/_sources/functions.md.txt +71 -5
- package/doc/dist/html/_sources/types.md.txt +147 -159
- package/doc/dist/html/benchmarks.html +2 -3
- package/doc/dist/html/changes.html +64 -35
- package/doc/dist/html/contribute.html +2 -3
- package/doc/dist/html/functions.html +73 -12
- package/doc/dist/html/genindex.html +2 -3
- package/doc/dist/html/index.html +6 -7
- package/doc/dist/html/memory.html +2 -3
- package/doc/dist/html/objects.inv +0 -0
- package/doc/dist/html/platforms.html +3 -4
- package/doc/dist/html/search.html +2 -3
- package/doc/dist/html/searchindex.js +1 -1
- package/doc/dist/html/start.html +2 -3
- package/doc/dist/html/types.html +238 -237
- package/doc/functions.md +71 -5
- package/doc/make.bat +1 -1
- package/doc/templates/badges.html +1 -2
- package/doc/types.md +149 -159
- package/package.json +3 -2
- package/qemu/qemu.js +1 -1
- package/src/abi_arm32.cc +208 -102
- package/src/abi_arm64.cc +239 -55
- package/src/abi_riscv64.cc +128 -40
- package/src/abi_x64_sysv.cc +135 -41
- package/src/abi_x64_win.cc +134 -40
- package/src/abi_x86.cc +182 -67
- package/src/call.cc +241 -26
- package/src/call.hh +15 -3
- package/src/ffi.cc +120 -31
- package/src/ffi.hh +19 -0
- package/src/index.js +4 -2
- package/src/parser.cc +3 -5
- package/src/util.cc +44 -1
- package/src/util.hh +4 -0
- package/test/async.js +1 -2
- package/test/callbacks.js +2 -3
- package/test/misc.c +64 -1
- package/test/raylib.js +1 -1
- package/test/sqlite.js +3 -3
- package/test/sync.js +108 -3
- package/build/qemu/2.0.1/koffi_darwin_arm64.tar.gz +0 -0
- package/build/qemu/2.0.1/koffi_darwin_x64.tar.gz +0 -0
- package/build/qemu/2.0.1/koffi_freebsd_arm64.tar.gz +0 -0
- package/build/qemu/2.0.1/koffi_freebsd_ia32.tar.gz +0 -0
- package/build/qemu/2.0.1/koffi_freebsd_x64.tar.gz +0 -0
- package/build/qemu/2.0.1/koffi_linux_arm32hf.tar.gz +0 -0
- package/build/qemu/2.0.1/koffi_linux_arm64.tar.gz +0 -0
- package/build/qemu/2.0.1/koffi_linux_ia32.tar.gz +0 -0
- package/build/qemu/2.0.1/koffi_linux_riscv64hf64.tar.gz +0 -0
- package/build/qemu/2.0.1/koffi_linux_x64.tar.gz +0 -0
- package/build/qemu/2.0.1/koffi_openbsd_ia32.tar.gz +0 -0
- package/build/qemu/2.0.1/koffi_openbsd_x64.tar.gz +0 -0
- package/build/qemu/2.0.1/koffi_win32_arm64.tar.gz +0 -0
- package/build/qemu/2.0.1/koffi_win32_ia32.tar.gz +0 -0
- package/build/qemu/2.0.1/koffi_win32_x64.tar.gz +0 -0
package/src/ffi.cc
CHANGED
|
@@ -42,6 +42,7 @@ namespace RG {
|
|
|
42
42
|
|
|
43
43
|
// Value does not matter, the tag system uses memory addresses
|
|
44
44
|
const int TypeInfoMarker = 0xDEADBEEF;
|
|
45
|
+
const int CastMarker = 0xDEADBEEF;
|
|
45
46
|
|
|
46
47
|
static bool ChangeMemorySize(const char *name, Napi::Value value, Size *out_size)
|
|
47
48
|
{
|
|
@@ -209,18 +210,40 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
|
|
|
209
210
|
|
|
210
211
|
std::string key = ((Napi::Value)keys[i]).As<Napi::String>();
|
|
211
212
|
Napi::Value value = obj[key];
|
|
213
|
+
int16_t align = 0;
|
|
212
214
|
|
|
213
215
|
member.name = DuplicateString(key.c_str(), &instance->str_alloc).ptr;
|
|
216
|
+
|
|
217
|
+
if (value.IsArray()) {
|
|
218
|
+
Napi::Array array = value.As<Napi::Array>();
|
|
219
|
+
|
|
220
|
+
if (array.Length() != 2 || !((Napi::Value)array[0u]).IsNumber()) {
|
|
221
|
+
ThrowError<Napi::Error>(env, "Member specifier array must contain alignement value and type");
|
|
222
|
+
return env.Null();
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
int64_t align64 = ((Napi::Value)array[0u]).As<Napi::Number>().Int64Value();
|
|
226
|
+
|
|
227
|
+
if (align64 < 1 || align64 > 64) {
|
|
228
|
+
ThrowError<Napi::Error>(env, "Alignment value must be between 1 and 64");
|
|
229
|
+
return env.Null();
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
value = array[1u];
|
|
233
|
+
align = (int16_t)align64;
|
|
234
|
+
}
|
|
235
|
+
|
|
214
236
|
member.type = ResolveType(value);
|
|
215
237
|
if (!member.type)
|
|
216
238
|
return env.Null();
|
|
217
|
-
if (member.type
|
|
218
|
-
member.type->primitive == PrimitiveKind::Prototype) {
|
|
239
|
+
if (!CanStoreType(member.type)) {
|
|
219
240
|
ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a member (maybe try %1 *)", member.type->name);
|
|
220
241
|
return env.Null();
|
|
221
242
|
}
|
|
222
243
|
|
|
223
|
-
|
|
244
|
+
if (!align) {
|
|
245
|
+
align = pad ? member.type->align : 1;
|
|
246
|
+
}
|
|
224
247
|
member.offset = (int16_t)AlignLen(type->size, align);
|
|
225
248
|
|
|
226
249
|
type->size = (int16_t)(member.offset + member.type->size);
|
|
@@ -264,7 +287,7 @@ static Napi::Value CreatePackedStructType(const Napi::CallbackInfo &info)
|
|
|
264
287
|
return CreateStructType(info, false);
|
|
265
288
|
}
|
|
266
289
|
|
|
267
|
-
static Napi::Value
|
|
290
|
+
static Napi::Value CreateOpaqueType(const Napi::CallbackInfo &info)
|
|
268
291
|
{
|
|
269
292
|
Napi::Env env = info.Env();
|
|
270
293
|
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
@@ -387,7 +410,7 @@ static Napi::Value EncodePointerDirection(const Napi::CallbackInfo &info, int di
|
|
|
387
410
|
return env.Null();
|
|
388
411
|
|
|
389
412
|
if (type->primitive != PrimitiveKind::Pointer) {
|
|
390
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 type, expected pointer type",
|
|
413
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 type, expected pointer type", type->name);
|
|
391
414
|
return env.Null();
|
|
392
415
|
}
|
|
393
416
|
|
|
@@ -440,7 +463,7 @@ static Napi::Value CreateDisposableType(const Napi::CallbackInfo &info)
|
|
|
440
463
|
if (src->primitive != PrimitiveKind::String &&
|
|
441
464
|
src->primitive != PrimitiveKind::String16 &&
|
|
442
465
|
src->primitive != PrimitiveKind::Pointer) {
|
|
443
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 type, expected pointer or string type",
|
|
466
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 type, expected pointer or string type", src->name);
|
|
444
467
|
return env.Null();
|
|
445
468
|
}
|
|
446
469
|
if (src->dispose) {
|
|
@@ -618,8 +641,8 @@ static bool ParseClassicFunction(Napi::Env env, Napi::String name, Napi::Value r
|
|
|
618
641
|
func->ret.type = ResolveType(ret);
|
|
619
642
|
if (!func->ret.type)
|
|
620
643
|
return false;
|
|
621
|
-
if (func->ret.type
|
|
622
|
-
ThrowError<Napi::
|
|
644
|
+
if (!CanReturnType(func->ret.type)) {
|
|
645
|
+
ThrowError<Napi::TypeError>(env, "You are not allowed to directly return %1 values (maybe try %1 *)", func->ret.type->name);
|
|
623
646
|
return false;
|
|
624
647
|
}
|
|
625
648
|
|
|
@@ -645,9 +668,7 @@ static bool ParseClassicFunction(Napi::Env env, Napi::String name, Napi::Value r
|
|
|
645
668
|
param.type = ResolveType(parameters[j], ¶m.directions);
|
|
646
669
|
if (!param.type)
|
|
647
670
|
return false;
|
|
648
|
-
if (param.type
|
|
649
|
-
param.type->primitive == PrimitiveKind::Array ||
|
|
650
|
-
param.type->primitive == PrimitiveKind::Prototype) {
|
|
671
|
+
if (!CanPassType(param.type)) {
|
|
651
672
|
ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter (maybe try %1 *)", param.type->name);
|
|
652
673
|
return false;
|
|
653
674
|
}
|
|
@@ -840,11 +861,17 @@ static Napi::Value GetTypeDefinition(const Napi::CallbackInfo &info)
|
|
|
840
861
|
case PrimitiveKind::Int8:
|
|
841
862
|
case PrimitiveKind::UInt8:
|
|
842
863
|
case PrimitiveKind::Int16:
|
|
864
|
+
case PrimitiveKind::Int16S:
|
|
843
865
|
case PrimitiveKind::UInt16:
|
|
866
|
+
case PrimitiveKind::UInt16S:
|
|
844
867
|
case PrimitiveKind::Int32:
|
|
868
|
+
case PrimitiveKind::Int32S:
|
|
845
869
|
case PrimitiveKind::UInt32:
|
|
870
|
+
case PrimitiveKind::UInt32S:
|
|
846
871
|
case PrimitiveKind::Int64:
|
|
872
|
+
case PrimitiveKind::Int64S:
|
|
847
873
|
case PrimitiveKind::UInt64:
|
|
874
|
+
case PrimitiveKind::UInt64S:
|
|
848
875
|
case PrimitiveKind::String:
|
|
849
876
|
case PrimitiveKind::String16:
|
|
850
877
|
case PrimitiveKind::Float32:
|
|
@@ -988,10 +1015,8 @@ static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
|
|
|
988
1015
|
param.type = ResolveType(info[i], ¶m.directions);
|
|
989
1016
|
if (RG_UNLIKELY(!param.type))
|
|
990
1017
|
return env.Null();
|
|
991
|
-
if (RG_UNLIKELY(param.type
|
|
992
|
-
|
|
993
|
-
param.type->primitive == PrimitiveKind::Prototype)) {
|
|
994
|
-
ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter (maybe try %1 *)", PrimitiveKindNames[(int)param.type->primitive]);
|
|
1018
|
+
if (RG_UNLIKELY(!CanPassType(param.type))) {
|
|
1019
|
+
ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter (maybe try %1 *)", param.type->name);
|
|
995
1020
|
return env.Null();
|
|
996
1021
|
}
|
|
997
1022
|
|
|
@@ -1384,17 +1409,6 @@ void LibraryHolder::Unref() const
|
|
|
1384
1409
|
}
|
|
1385
1410
|
}
|
|
1386
1411
|
|
|
1387
|
-
static inline PrimitiveKind GetIntegerPrimitive(Size len, bool sign)
|
|
1388
|
-
{
|
|
1389
|
-
switch (len) {
|
|
1390
|
-
case 1: return sign ? PrimitiveKind::Int8 : PrimitiveKind::UInt8;
|
|
1391
|
-
case 2: return sign ? PrimitiveKind::Int16 : PrimitiveKind::UInt16;
|
|
1392
|
-
case 4: return sign ? PrimitiveKind::Int32 : PrimitiveKind::UInt32;
|
|
1393
|
-
case 8: return sign ? PrimitiveKind::Int64 : PrimitiveKind::UInt64;
|
|
1394
|
-
}
|
|
1395
|
-
|
|
1396
|
-
RG_UNREACHABLE();
|
|
1397
|
-
}
|
|
1398
1412
|
|
|
1399
1413
|
static void RegisterPrimitiveType(Napi::Env env, Napi::Object map, std::initializer_list<const char *> names,
|
|
1400
1414
|
PrimitiveKind primitive, int16_t size, int16_t align, const char *ref = nullptr)
|
|
@@ -1432,8 +1446,34 @@ static void RegisterPrimitiveType(Napi::Env env, Napi::Object map, std::initiali
|
|
|
1432
1446
|
}
|
|
1433
1447
|
}
|
|
1434
1448
|
|
|
1449
|
+
static inline PrimitiveKind GetSignPrimitive(Size len, bool sign)
|
|
1450
|
+
{
|
|
1451
|
+
switch (len) {
|
|
1452
|
+
case 1: return sign ? PrimitiveKind::Int8 : PrimitiveKind::UInt8;
|
|
1453
|
+
case 2: return sign ? PrimitiveKind::Int16 : PrimitiveKind::UInt16;
|
|
1454
|
+
case 4: return sign ? PrimitiveKind::Int32 : PrimitiveKind::UInt32;
|
|
1455
|
+
case 8: return sign ? PrimitiveKind::Int64 : PrimitiveKind::UInt64;
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1458
|
+
RG_UNREACHABLE();
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
static inline PrimitiveKind GetLittleEndianPrimitive(PrimitiveKind kind)
|
|
1462
|
+
{
|
|
1463
|
+
// Sensitive to endianness
|
|
1464
|
+
return kind;
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1467
|
+
static inline PrimitiveKind GetBigEndianPrimitive(PrimitiveKind kind)
|
|
1468
|
+
{
|
|
1469
|
+
// Sensitive to endianness
|
|
1470
|
+
return (PrimitiveKind)((int)kind + 1);
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1435
1473
|
static Napi::Object InitBaseTypes(Napi::Env env)
|
|
1436
1474
|
{
|
|
1475
|
+
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
1476
|
+
|
|
1437
1477
|
Napi::Object types = Napi::Object::New(env);
|
|
1438
1478
|
|
|
1439
1479
|
RegisterPrimitiveType(env, types, {"void"}, PrimitiveKind::Void, 0, 0);
|
|
@@ -1444,19 +1484,32 @@ static Napi::Object InitBaseTypes(Napi::Env env)
|
|
|
1444
1484
|
RegisterPrimitiveType(env, types, {"unsigned char", "uchar"}, PrimitiveKind::UInt8, 1, 1);
|
|
1445
1485
|
RegisterPrimitiveType(env, types, {"char16_t", "char16"}, PrimitiveKind::Int16, 2, 2);
|
|
1446
1486
|
RegisterPrimitiveType(env, types, {"int16_t", "int16"}, PrimitiveKind::Int16, 2, 2);
|
|
1487
|
+
RegisterPrimitiveType(env, types, {"int16_le_t", "int16_le"}, GetLittleEndianPrimitive(PrimitiveKind::Int16), 2, 2);
|
|
1488
|
+
RegisterPrimitiveType(env, types, {"int16_be_t", "int16_be"}, GetBigEndianPrimitive(PrimitiveKind::Int16), 2, 2);
|
|
1447
1489
|
RegisterPrimitiveType(env, types, {"uint16_t", "uint16"}, PrimitiveKind::UInt16, 2, 2);
|
|
1490
|
+
RegisterPrimitiveType(env, types, {"uint16_le_t", "uint16_le"}, GetLittleEndianPrimitive(PrimitiveKind::UInt16), 2, 2);
|
|
1491
|
+
RegisterPrimitiveType(env, types, {"uint16_be_t", "uint16_be"}, GetBigEndianPrimitive(PrimitiveKind::UInt16), 2, 2);
|
|
1448
1492
|
RegisterPrimitiveType(env, types, {"short"}, PrimitiveKind::Int16, 2, 2);
|
|
1449
1493
|
RegisterPrimitiveType(env, types, {"unsigned short", "ushort"}, PrimitiveKind::UInt16, 2, 2);
|
|
1450
1494
|
RegisterPrimitiveType(env, types, {"int32_t", "int32"}, PrimitiveKind::Int32, 4, 4);
|
|
1495
|
+
RegisterPrimitiveType(env, types, {"int32_le_t", "int32_le"}, GetLittleEndianPrimitive(PrimitiveKind::Int32), 4, 4);
|
|
1496
|
+
RegisterPrimitiveType(env, types, {"int32_be_t", "int32_be"}, GetBigEndianPrimitive(PrimitiveKind::Int32), 4, 4);
|
|
1451
1497
|
RegisterPrimitiveType(env, types, {"uint32_t", "uint32"}, PrimitiveKind::UInt32, 4, 4);
|
|
1498
|
+
RegisterPrimitiveType(env, types, {"uint32_le_t", "uint32_le"}, GetLittleEndianPrimitive(PrimitiveKind::UInt32), 4, 4);
|
|
1499
|
+
RegisterPrimitiveType(env, types, {"uint32_be_t", "uint32_be"}, GetBigEndianPrimitive(PrimitiveKind::UInt32), 4, 4);
|
|
1452
1500
|
RegisterPrimitiveType(env, types, {"int"}, PrimitiveKind::Int32, 4, 4);
|
|
1453
1501
|
RegisterPrimitiveType(env, types, {"unsigned int", "uint"}, PrimitiveKind::UInt32, 4, 4);
|
|
1454
1502
|
RegisterPrimitiveType(env, types, {"int64_t", "int64"}, PrimitiveKind::Int64, 8, alignof(int64_t));
|
|
1503
|
+
RegisterPrimitiveType(env, types, {"int64_le_t", "int64_le"}, GetLittleEndianPrimitive(PrimitiveKind::Int64), 8, alignof(int64_t));
|
|
1504
|
+
RegisterPrimitiveType(env, types, {"int64_be_t", "int64_be"}, GetBigEndianPrimitive(PrimitiveKind::Int64), 8, alignof(int64_t));
|
|
1455
1505
|
RegisterPrimitiveType(env, types, {"uint64_t", "uint64"}, PrimitiveKind::UInt64, 8, alignof(int64_t));
|
|
1456
|
-
RegisterPrimitiveType(env, types, {"
|
|
1457
|
-
RegisterPrimitiveType(env, types, {"
|
|
1458
|
-
RegisterPrimitiveType(env, types, {"
|
|
1459
|
-
RegisterPrimitiveType(env, types, {"
|
|
1506
|
+
RegisterPrimitiveType(env, types, {"uint64_le_t", "uint64_le"}, GetLittleEndianPrimitive(PrimitiveKind::UInt64), 8, alignof(int64_t));
|
|
1507
|
+
RegisterPrimitiveType(env, types, {"uint64_be_t", "uint64_be"}, GetBigEndianPrimitive(PrimitiveKind::UInt64), 8, alignof(int64_t));
|
|
1508
|
+
RegisterPrimitiveType(env, types, {"intptr_t", "intptr"}, GetSignPrimitive(RG_SIZE(intptr_t), true), RG_SIZE(intptr_t), alignof(intptr_t));
|
|
1509
|
+
RegisterPrimitiveType(env, types, {"uintptr_t", "uintptr"}, GetSignPrimitive(RG_SIZE(intptr_t), false), RG_SIZE(intptr_t), alignof(intptr_t));
|
|
1510
|
+
RegisterPrimitiveType(env, types, {"size_t"}, GetSignPrimitive(RG_SIZE(size_t), false), RG_SIZE(size_t), alignof(size_t));
|
|
1511
|
+
RegisterPrimitiveType(env, types, {"long"}, GetSignPrimitive(RG_SIZE(long), true), RG_SIZE(long), alignof(long));
|
|
1512
|
+
RegisterPrimitiveType(env, types, {"unsigned long", "ulong"}, GetSignPrimitive(RG_SIZE(long), false), RG_SIZE(long), alignof(long));
|
|
1460
1513
|
RegisterPrimitiveType(env, types, {"long long", "longlong"}, PrimitiveKind::Int64, RG_SIZE(int64_t), alignof(int64_t));
|
|
1461
1514
|
RegisterPrimitiveType(env, types, {"unsigned long long", "ulonglong"}, PrimitiveKind::UInt64, RG_SIZE(uint64_t), alignof(uint64_t));
|
|
1462
1515
|
RegisterPrimitiveType(env, types, {"float", "float32"}, PrimitiveKind::Float32, 4, alignof(float));
|
|
@@ -1464,6 +1517,9 @@ static Napi::Object InitBaseTypes(Napi::Env env)
|
|
|
1464
1517
|
RegisterPrimitiveType(env, types, {"char *", "str", "string"}, PrimitiveKind::String, RG_SIZE(void *), alignof(void *), "char");
|
|
1465
1518
|
RegisterPrimitiveType(env, types, {"char16_t *", "char16 *", "str16", "string16"}, PrimitiveKind::String16, RG_SIZE(void *), alignof(void *), "char16_t");
|
|
1466
1519
|
|
|
1520
|
+
instance->void_type = instance->types_map.FindValue("void", nullptr);
|
|
1521
|
+
RG_ASSERT(instance->void_type);
|
|
1522
|
+
|
|
1467
1523
|
types.Freeze();
|
|
1468
1524
|
|
|
1469
1525
|
return types;
|
|
@@ -1515,6 +1571,37 @@ InstanceData::~InstanceData()
|
|
|
1515
1571
|
}
|
|
1516
1572
|
}
|
|
1517
1573
|
|
|
1574
|
+
static Napi::Value CastValue(const Napi::CallbackInfo &info)
|
|
1575
|
+
{
|
|
1576
|
+
Napi::Env env = info.Env();
|
|
1577
|
+
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
1578
|
+
|
|
1579
|
+
if (RG_UNLIKELY(info.Length() < 2)) {
|
|
1580
|
+
ThrowError<Napi::TypeError>(env, "Expected 2 arguments, got %1", info.Length());
|
|
1581
|
+
return env.Null();
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
Napi::Value value = info[0];
|
|
1585
|
+
|
|
1586
|
+
const TypeInfo *type = ResolveType(info[1]);
|
|
1587
|
+
if (RG_UNLIKELY(!type))
|
|
1588
|
+
return env.Null();
|
|
1589
|
+
if (type->primitive != PrimitiveKind::Pointer) {
|
|
1590
|
+
ThrowError<Napi::TypeError>(env, "Only pointer types can be used for casting");
|
|
1591
|
+
return env.Null();
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1594
|
+
ValueCast *cast = new ValueCast;
|
|
1595
|
+
|
|
1596
|
+
cast->ref.Reset(value, 1);
|
|
1597
|
+
cast->type = type;
|
|
1598
|
+
|
|
1599
|
+
Napi::External<ValueCast> external = Napi::External<ValueCast>::New(env, cast, [](Napi::Env, ValueCast *cast) { delete cast; });
|
|
1600
|
+
SetValueTag(instance, external, &CastMarker);
|
|
1601
|
+
|
|
1602
|
+
return external;
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1518
1605
|
template <typename Func>
|
|
1519
1606
|
static void SetExports(Napi::Env env, Func func)
|
|
1520
1607
|
{
|
|
@@ -1522,7 +1609,7 @@ static void SetExports(Napi::Env env, Func func)
|
|
|
1522
1609
|
|
|
1523
1610
|
func("struct", Napi::Function::New(env, CreatePaddedStructType));
|
|
1524
1611
|
func("pack", Napi::Function::New(env, CreatePackedStructType));
|
|
1525
|
-
func("
|
|
1612
|
+
func("opaque", Napi::Function::New(env, CreateOpaqueType));
|
|
1526
1613
|
func("pointer", Napi::Function::New(env, CreatePointerType));
|
|
1527
1614
|
func("array", Napi::Function::New(env, CreateArrayType));
|
|
1528
1615
|
func("callback", Napi::Function::New(env, CreateCallbackType));
|
|
@@ -1545,6 +1632,8 @@ static void SetExports(Napi::Env env, Func func)
|
|
|
1545
1632
|
func("register", Napi::Function::New(env, RegisterCallback));
|
|
1546
1633
|
func("unregister", Napi::Function::New(env, UnregisterCallback));
|
|
1547
1634
|
|
|
1635
|
+
func("as", Napi::Function::New(env, CastValue));
|
|
1636
|
+
|
|
1548
1637
|
#if defined(_WIN32)
|
|
1549
1638
|
func("extension", Napi::String::New(env, ".dll"));
|
|
1550
1639
|
#elif defined(__APPLE__)
|
package/src/ffi.hh
CHANGED
|
@@ -32,6 +32,7 @@ static const Size MaxOutParameters = 4;
|
|
|
32
32
|
static const Size MaxTrampolines = 16;
|
|
33
33
|
|
|
34
34
|
extern const int TypeInfoMarker;
|
|
35
|
+
extern const int CastMarker;
|
|
35
36
|
|
|
36
37
|
enum class PrimitiveKind {
|
|
37
38
|
Void,
|
|
@@ -39,11 +40,17 @@ enum class PrimitiveKind {
|
|
|
39
40
|
Int8,
|
|
40
41
|
UInt8,
|
|
41
42
|
Int16,
|
|
43
|
+
Int16S,
|
|
42
44
|
UInt16,
|
|
45
|
+
UInt16S,
|
|
43
46
|
Int32,
|
|
47
|
+
Int32S,
|
|
44
48
|
UInt32,
|
|
49
|
+
UInt32S,
|
|
45
50
|
Int64,
|
|
51
|
+
Int64S,
|
|
46
52
|
UInt64,
|
|
53
|
+
UInt64S,
|
|
47
54
|
String,
|
|
48
55
|
String16,
|
|
49
56
|
Pointer,
|
|
@@ -60,11 +67,17 @@ static const char *const PrimitiveKindNames[] = {
|
|
|
60
67
|
"Int8",
|
|
61
68
|
"UInt8",
|
|
62
69
|
"Int16",
|
|
70
|
+
"Int16S",
|
|
63
71
|
"UInt16",
|
|
72
|
+
"UInt16S",
|
|
64
73
|
"Int32",
|
|
74
|
+
"Int32S",
|
|
65
75
|
"UInt32",
|
|
76
|
+
"UInt32S",
|
|
66
77
|
"Int64",
|
|
78
|
+
"Int64S",
|
|
67
79
|
"UInt64",
|
|
80
|
+
"UInt64S",
|
|
68
81
|
"String",
|
|
69
82
|
"String16",
|
|
70
83
|
"Pointer",
|
|
@@ -171,6 +184,11 @@ struct ParameterInfo {
|
|
|
171
184
|
#endif
|
|
172
185
|
};
|
|
173
186
|
|
|
187
|
+
struct ValueCast {
|
|
188
|
+
Napi::Reference<Napi::Value> ref;
|
|
189
|
+
const TypeInfo *type;
|
|
190
|
+
};
|
|
191
|
+
|
|
174
192
|
// Also used for callbacks, even though many members are not used in this case
|
|
175
193
|
struct FunctionInfo {
|
|
176
194
|
mutable std::atomic_int refcount {1};
|
|
@@ -230,6 +248,7 @@ struct InstanceData {
|
|
|
230
248
|
|
|
231
249
|
bool debug;
|
|
232
250
|
uint64_t tag_lower;
|
|
251
|
+
const TypeInfo *void_type;
|
|
233
252
|
|
|
234
253
|
LocalArray<InstanceMemory *, 9> memories;
|
|
235
254
|
int temporaries = 0;
|
package/src/index.js
CHANGED
|
@@ -15,7 +15,9 @@
|
|
|
15
15
|
|
|
16
16
|
'use strict';
|
|
17
17
|
|
|
18
|
-
const
|
|
18
|
+
const util = require('util');
|
|
19
19
|
|
|
20
|
-
let filename =
|
|
20
|
+
let filename = __dirname + '/../build/koffi.node';
|
|
21
21
|
module.exports = require(filename);
|
|
22
|
+
|
|
23
|
+
module.exports.handle = util.deprecate(module.exports.opaque, 'The koffi.handle() function was deprecated in Koffi 2.1, use koffi.opaque() instead', 'KOFFI001');
|
package/src/parser.cc
CHANGED
|
@@ -28,8 +28,8 @@ bool PrototypeParser::Parse(const char *str, FunctionInfo *out_func)
|
|
|
28
28
|
Tokenize(str);
|
|
29
29
|
|
|
30
30
|
out_func->ret.type = ParseType();
|
|
31
|
-
if (out_func->ret.type
|
|
32
|
-
MarkError("You are not allowed to directly return
|
|
31
|
+
if (!CanReturnType(out_func->ret.type)) {
|
|
32
|
+
MarkError("You are not allowed to directly return %1 values (maybe try %1 *)", out_func->ret.type->name);
|
|
33
33
|
return false;
|
|
34
34
|
}
|
|
35
35
|
if (Match("__cdecl")) {
|
|
@@ -65,9 +65,7 @@ bool PrototypeParser::Parse(const char *str, FunctionInfo *out_func)
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
param.type = ParseType();
|
|
68
|
-
if (param.type
|
|
69
|
-
param.type->primitive == PrimitiveKind::Array ||
|
|
70
|
-
param.type->primitive == PrimitiveKind::Prototype) {
|
|
68
|
+
if (!CanPassType(param.type)) {
|
|
71
69
|
MarkError("Type %1 cannot be used as a parameter (maybe try %1 *)", param.type->name);
|
|
72
70
|
return false;
|
|
73
71
|
}
|
package/src/util.cc
CHANGED
|
@@ -170,10 +170,53 @@ const TypeInfo *MakePointerType(InstanceData *instance, const TypeInfo *ref, int
|
|
|
170
170
|
return ref;
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
+
bool CanPassType(const TypeInfo *type)
|
|
174
|
+
{
|
|
175
|
+
if (type->primitive == PrimitiveKind::Void)
|
|
176
|
+
return false;
|
|
177
|
+
if (type->primitive == PrimitiveKind::Array)
|
|
178
|
+
return false;
|
|
179
|
+
if (type->primitive == PrimitiveKind::Prototype)
|
|
180
|
+
return false;
|
|
181
|
+
|
|
182
|
+
return true;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
bool CanReturnType(const TypeInfo *type)
|
|
186
|
+
{
|
|
187
|
+
if (type->primitive == PrimitiveKind::Void && !TestStr(type->name, "void"))
|
|
188
|
+
return false;
|
|
189
|
+
if (type->primitive == PrimitiveKind::Array)
|
|
190
|
+
return false;
|
|
191
|
+
if (type->primitive == PrimitiveKind::Prototype)
|
|
192
|
+
return false;
|
|
193
|
+
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
bool CanStoreType(const TypeInfo *type)
|
|
198
|
+
{
|
|
199
|
+
if (type->primitive == PrimitiveKind::Void)
|
|
200
|
+
return false;
|
|
201
|
+
if (type->primitive == PrimitiveKind::Prototype)
|
|
202
|
+
return false;
|
|
203
|
+
|
|
204
|
+
return true;
|
|
205
|
+
}
|
|
206
|
+
|
|
173
207
|
const char *GetValueType(const InstanceData *instance, Napi::Value value)
|
|
174
208
|
{
|
|
209
|
+
if (CheckValueTag(instance, value, &CastMarker)) {
|
|
210
|
+
Napi::External<ValueCast> external = value.As<Napi::External<ValueCast>>();
|
|
211
|
+
ValueCast *cast = external.Data();
|
|
212
|
+
|
|
213
|
+
return cast->type->name;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (CheckValueTag(instance, value, &TypeInfoMarker))
|
|
217
|
+
return "Type";
|
|
175
218
|
for (const TypeInfo &type: instance->types) {
|
|
176
|
-
if (CheckValueTag(instance, value, type.ref.marker))
|
|
219
|
+
if (type.ref.marker && CheckValueTag(instance, value, type.ref.marker))
|
|
177
220
|
return type.name;
|
|
178
221
|
}
|
|
179
222
|
|
package/src/util.hh
CHANGED
|
@@ -71,6 +71,10 @@ const TypeInfo *ResolveType(Napi::Value value, int *out_directions = nullptr);
|
|
|
71
71
|
const TypeInfo *ResolveType(InstanceData *instance, Span<const char> str, int *out_directions = nullptr);
|
|
72
72
|
const TypeInfo *MakePointerType(InstanceData *instance, const TypeInfo *type, int count = 1);
|
|
73
73
|
|
|
74
|
+
bool CanPassType(const TypeInfo *type);
|
|
75
|
+
bool CanReturnType(const TypeInfo *type);
|
|
76
|
+
bool CanStoreType(const TypeInfo *type);
|
|
77
|
+
|
|
74
78
|
// Can be slow, only use for error messages
|
|
75
79
|
const char *GetValueType(const InstanceData *instance, Napi::Value value);
|
|
76
80
|
|
package/test/async.js
CHANGED
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
|
|
16
16
|
const koffi = require('./build/koffi.node');
|
|
17
17
|
const assert = require('assert');
|
|
18
|
-
const path = require('path');
|
|
19
18
|
|
|
20
19
|
const PackedBFG = koffi.pack('PackedBFG', {
|
|
21
20
|
a: 'int8_t',
|
|
@@ -42,7 +41,7 @@ async function main() {
|
|
|
42
41
|
}
|
|
43
42
|
|
|
44
43
|
async function test() {
|
|
45
|
-
const lib_filename =
|
|
44
|
+
const lib_filename = __dirname + '/build/misc' + koffi.extension;
|
|
46
45
|
const lib = koffi.load(lib_filename);
|
|
47
46
|
|
|
48
47
|
const ConcatenateToInt1 = lib.func('ConcatenateToInt1', 'int64_t', Array(12).fill('int8_t'));
|
package/test/callbacks.js
CHANGED
|
@@ -15,11 +15,10 @@
|
|
|
15
15
|
|
|
16
16
|
const koffi = require('./build/koffi.node');
|
|
17
17
|
const assert = require('assert');
|
|
18
|
-
const path = require('path');
|
|
19
18
|
|
|
20
19
|
const BFG = koffi.struct('BFG', {
|
|
21
20
|
a: 'int8_t',
|
|
22
|
-
b: 'int64_t',
|
|
21
|
+
b: [16, 'int64_t'],
|
|
23
22
|
c: 'char',
|
|
24
23
|
d: 'str',
|
|
25
24
|
e: 'short',
|
|
@@ -55,7 +54,7 @@ async function main() {
|
|
|
55
54
|
}
|
|
56
55
|
|
|
57
56
|
async function test() {
|
|
58
|
-
const lib_filename =
|
|
57
|
+
const lib_filename = __dirname + '/build/misc' + koffi.extension;
|
|
59
58
|
const lib = koffi.load(lib_filename);
|
|
60
59
|
|
|
61
60
|
const CallJS = lib.func('int CallJS(const char *str, SimpleCallback *cb)');
|
package/test/misc.c
CHANGED
|
@@ -90,7 +90,7 @@ typedef struct IJK8 { int64_t i; int64_t j; int64_t k; } IJK8;
|
|
|
90
90
|
|
|
91
91
|
typedef struct BFG {
|
|
92
92
|
int8_t a;
|
|
93
|
-
int64_t b;
|
|
93
|
+
char _pad1[15]; int64_t b;
|
|
94
94
|
signed char c;
|
|
95
95
|
const char *d;
|
|
96
96
|
short e;
|
|
@@ -143,6 +143,21 @@ typedef struct StructCallbacks {
|
|
|
143
143
|
IntCallback *third;
|
|
144
144
|
} StructCallbacks;
|
|
145
145
|
|
|
146
|
+
typedef struct EndianInts {
|
|
147
|
+
int16_t i16le;
|
|
148
|
+
int16_t i16be;
|
|
149
|
+
uint16_t u16le;
|
|
150
|
+
uint16_t u16be;
|
|
151
|
+
int32_t i32le;
|
|
152
|
+
int32_t i32be;
|
|
153
|
+
uint32_t u32le;
|
|
154
|
+
uint32_t u32be;
|
|
155
|
+
int64_t i64le;
|
|
156
|
+
int64_t i64be;
|
|
157
|
+
uint64_t u64le;
|
|
158
|
+
uint64_t u64be;
|
|
159
|
+
} EndianInts;
|
|
160
|
+
|
|
146
161
|
EXPORT int8_t GetMinusOne1(void)
|
|
147
162
|
{
|
|
148
163
|
return -1;
|
|
@@ -399,6 +414,15 @@ EXPORT PackedBFG FASTCALL MakePackedBFG(int x, double y, PackedBFG *p, const cha
|
|
|
399
414
|
return bfg;
|
|
400
415
|
}
|
|
401
416
|
|
|
417
|
+
EXPORT void MakePolymorphBFG(int type, int x, double y, const char *str, void *p)
|
|
418
|
+
{
|
|
419
|
+
if (type == 0) {
|
|
420
|
+
MakeBFG(p, x, y, str);
|
|
421
|
+
} else if (type == 1) {
|
|
422
|
+
MakePackedBFG(x, y, p, str);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
402
426
|
#ifdef _WIN32
|
|
403
427
|
// Exported by DEF file
|
|
404
428
|
const char *ReturnBigString(const char *str)
|
|
@@ -633,3 +657,42 @@ EXPORT int CallCallback(int x)
|
|
|
633
657
|
{
|
|
634
658
|
return callback(x);
|
|
635
659
|
}
|
|
660
|
+
|
|
661
|
+
EXPORT void ReverseBytes(void *p, int len)
|
|
662
|
+
{
|
|
663
|
+
uint8_t *bytes = (uint8_t *)p;
|
|
664
|
+
|
|
665
|
+
for (int i = 0; i < len / 2; i++) {
|
|
666
|
+
uint8_t tmp = bytes[i];
|
|
667
|
+
bytes[i] = bytes[len - i - 1];
|
|
668
|
+
bytes[len - i - 1] = tmp;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
EXPORT void CopyEndianInts1(EndianInts ints, uint8_t buf[56])
|
|
673
|
+
{
|
|
674
|
+
memcpy(buf, &ints, sizeof(ints));
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
EXPORT void CopyEndianInts2(int16_t i16le, int16_t i16be, uint16_t u16le, uint16_t u16be,
|
|
678
|
+
int32_t i32le, int32_t i32be, uint32_t u32le, uint32_t u32be,
|
|
679
|
+
int64_t i64le, int64_t i64be, uint64_t u64le, uint64_t u64be,
|
|
680
|
+
EndianInts *out)
|
|
681
|
+
{
|
|
682
|
+
out->i16le = i16le;
|
|
683
|
+
out->i16be = i16be;
|
|
684
|
+
out->u16le = u16le;
|
|
685
|
+
out->u16be = u16be;
|
|
686
|
+
out->i32le = i32le;
|
|
687
|
+
out->i32be = i32be;
|
|
688
|
+
out->u32le = u32le;
|
|
689
|
+
out->u32be = u32be;
|
|
690
|
+
out->i64le = i64le;
|
|
691
|
+
out->i64be = i64be;
|
|
692
|
+
out->u64le = u64le;
|
|
693
|
+
out->u64be = u64be;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
EXPORT uint16_t ReturnEndianInt2(uint16_t v) { return v; }
|
|
697
|
+
EXPORT uint32_t ReturnEndianInt4(uint32_t v) { return v; }
|
|
698
|
+
EXPORT uint64_t ReturnEndianInt8(uint64_t v) { return v; }
|
package/test/raylib.js
CHANGED
|
@@ -83,7 +83,7 @@ async function main() {
|
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
async function test() {
|
|
86
|
-
let lib_filename =
|
|
86
|
+
let lib_filename = __dirname + '/build/raylib' + koffi.extension;
|
|
87
87
|
let lib = koffi.load(lib_filename);
|
|
88
88
|
|
|
89
89
|
const InitWindow = lib.func('InitWindow', 'void', ['int', 'int', 'str']);
|
package/test/sqlite.js
CHANGED
|
@@ -20,8 +20,8 @@ const fs = require('fs');
|
|
|
20
20
|
const os = require('os');
|
|
21
21
|
const path = require('path');
|
|
22
22
|
|
|
23
|
-
const sqlite3 = koffi.
|
|
24
|
-
const sqlite3_stmt = koffi.
|
|
23
|
+
const sqlite3 = koffi.opaque('sqlite3');
|
|
24
|
+
const sqlite3_stmt = koffi.opaque('sqlite3_stmt');
|
|
25
25
|
|
|
26
26
|
main();
|
|
27
27
|
|
|
@@ -36,7 +36,7 @@ async function main() {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
async function test() {
|
|
39
|
-
let lib_filename =
|
|
39
|
+
let lib_filename = __dirname + '/build/sqlite3' + koffi.extension;
|
|
40
40
|
let lib = koffi.load(lib_filename);
|
|
41
41
|
|
|
42
42
|
const sqlite3_open_v2 = lib.func('sqlite3_open_v2', 'int', ['str', koffi.out(koffi.pointer(sqlite3, 2)), 'int', 'str']);
|