koffi 2.1.5 → 2.2.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/ChangeLog.md +21 -1
- package/doc/Makefile +1 -1
- package/doc/callbacks.md +175 -0
- package/doc/changes.md +2 -3
- package/doc/conf.py +29 -6
- package/doc/functions.md +39 -124
- package/doc/index.rst +1 -0
- package/doc/make.bat +1 -1
- package/doc/types.md +36 -9
- package/package.json +2 -2
- package/src/core/libcc/libcc.cc +89 -27
- package/src/core/libcc/libcc.hh +74 -39
- package/src/koffi/build/2.2.1/koffi_darwin_arm64.tar.gz +0 -0
- package/src/koffi/build/2.2.1/koffi_darwin_x64.tar.gz +0 -0
- package/src/koffi/build/2.2.1/koffi_freebsd_arm64.tar.gz +0 -0
- package/src/koffi/build/2.2.1/koffi_freebsd_ia32.tar.gz +0 -0
- package/src/koffi/build/2.2.1/koffi_freebsd_x64.tar.gz +0 -0
- package/src/koffi/build/2.2.1/koffi_linux_arm32hf.tar.gz +0 -0
- package/src/koffi/build/2.2.1/koffi_linux_arm64.tar.gz +0 -0
- package/src/koffi/build/2.2.1/koffi_linux_ia32.tar.gz +0 -0
- package/src/koffi/build/2.2.1/koffi_linux_riscv64hf64.tar.gz +0 -0
- package/src/koffi/build/2.2.1/koffi_linux_x64.tar.gz +0 -0
- package/src/koffi/build/2.2.1/koffi_openbsd_ia32.tar.gz +0 -0
- package/src/koffi/build/2.2.1/koffi_openbsd_x64.tar.gz +0 -0
- package/src/koffi/build/2.2.1/koffi_win32_arm64.tar.gz +0 -0
- package/src/koffi/build/2.2.1/koffi_win32_ia32.tar.gz +0 -0
- package/src/koffi/build/2.2.1/koffi_win32_x64.tar.gz +0 -0
- package/src/koffi/qemu/qemu.js +3 -1
- package/src/koffi/src/abi_arm32.cc +26 -23
- package/src/koffi/src/abi_arm64.cc +25 -22
- package/src/koffi/src/abi_riscv64.cc +21 -18
- package/src/koffi/src/abi_x64_sysv.cc +20 -17
- package/src/koffi/src/abi_x64_win.cc +19 -16
- package/src/koffi/src/abi_x86.cc +23 -20
- package/src/koffi/src/call.cc +222 -607
- package/src/koffi/src/call.hh +7 -11
- package/src/koffi/src/ffi.cc +229 -29
- package/src/koffi/src/ffi.hh +6 -2
- package/src/koffi/src/parser.cc +3 -9
- package/src/koffi/src/util.cc +546 -8
- package/src/koffi/src/util.hh +8 -2
- package/src/koffi/test/CMakeLists.txt +3 -3
- package/src/koffi/test/callbacks.js +89 -0
- package/src/koffi/test/misc.c +78 -0
- package/src/koffi/test/raylib.js +2 -2
- package/src/koffi/test/sqlite.js +1 -1
- package/src/koffi/test/sync.js +28 -6
- package/vendor/brotli/c/common/platform.h +2 -0
- package/vendor/sqlite3mc/sqlite3.c +243532 -0
- package/vendor/sqlite3mc/sqlite3.h +12887 -0
- package/src/koffi/build/2.1.5/koffi_darwin_arm64.tar.gz +0 -0
- package/src/koffi/build/2.1.5/koffi_darwin_x64.tar.gz +0 -0
- package/src/koffi/build/2.1.5/koffi_freebsd_arm64.tar.gz +0 -0
- package/src/koffi/build/2.1.5/koffi_freebsd_ia32.tar.gz +0 -0
- package/src/koffi/build/2.1.5/koffi_freebsd_x64.tar.gz +0 -0
- package/src/koffi/build/2.1.5/koffi_linux_arm32hf.tar.gz +0 -0
- package/src/koffi/build/2.1.5/koffi_linux_arm64.tar.gz +0 -0
- package/src/koffi/build/2.1.5/koffi_linux_ia32.tar.gz +0 -0
- package/src/koffi/build/2.1.5/koffi_linux_riscv64hf64.tar.gz +0 -0
- package/src/koffi/build/2.1.5/koffi_linux_x64.tar.gz +0 -0
- package/src/koffi/build/2.1.5/koffi_openbsd_ia32.tar.gz +0 -0
- package/src/koffi/build/2.1.5/koffi_openbsd_x64.tar.gz +0 -0
- package/src/koffi/build/2.1.5/koffi_win32_arm64.tar.gz +0 -0
- package/src/koffi/build/2.1.5/koffi_win32_ia32.tar.gz +0 -0
- package/src/koffi/build/2.1.5/koffi_win32_x64.tar.gz +0 -0
package/src/koffi/src/call.hh
CHANGED
|
@@ -65,7 +65,7 @@ class alignas(8) CallData {
|
|
|
65
65
|
} result;
|
|
66
66
|
uint8_t *return_ptr = nullptr;
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
BlockAllocator call_alloc;
|
|
69
69
|
|
|
70
70
|
public:
|
|
71
71
|
CallData(Napi::Env env, InstanceData *instance, const FunctionInfo *func, InstanceMemory *mem);
|
|
@@ -97,20 +97,16 @@ private:
|
|
|
97
97
|
template <typename T = uint8_t>
|
|
98
98
|
T *AllocHeap(Size size, Size align);
|
|
99
99
|
|
|
100
|
-
bool PushString(Napi::Value value, const char **out_str);
|
|
101
|
-
|
|
100
|
+
bool PushString(Napi::Value value, int directions, const char **out_str);
|
|
101
|
+
Size PushStringValue(Napi::Value value, const char **out_str);
|
|
102
|
+
bool PushString16(Napi::Value value, int directions, const char16_t **out_str16);
|
|
103
|
+
Size PushString16Value(Napi::Value value, const char16_t **out_str16);
|
|
102
104
|
bool PushObject(Napi::Object obj, const TypeInfo *type, uint8_t *origin, int16_t realign = 0);
|
|
103
|
-
bool PushNormalArray(Napi::Array array, Size len, const TypeInfo *
|
|
104
|
-
bool PushTypedArray(Napi::TypedArray array, Size len, const TypeInfo *
|
|
105
|
+
bool PushNormalArray(Napi::Array array, Size len, const TypeInfo *type, uint8_t *origin, int16_t realign = 0);
|
|
106
|
+
bool PushTypedArray(Napi::TypedArray array, Size len, const TypeInfo *type, uint8_t *origin, int16_t realign = 0);
|
|
105
107
|
bool PushStringArray(Napi::Value value, const TypeInfo *type, uint8_t *origin);
|
|
106
108
|
bool PushPointer(Napi::Value value, const TypeInfo *type, int directions, void **out_ptr);
|
|
107
109
|
|
|
108
|
-
void PopObject(Napi::Object obj, const uint8_t *origin, const TypeInfo *type, int16_t realign = 0);
|
|
109
|
-
Napi::Object PopObject(const uint8_t *origin, const TypeInfo *type, int16_t realign = 0);
|
|
110
|
-
void PopNormalArray(Napi::Array array, const uint8_t *origin, const TypeInfo *ref, int16_t realign = 0);
|
|
111
|
-
void PopTypedArray(Napi::TypedArray array, const uint8_t *origin, const TypeInfo *ref, int16_t realign = 0);
|
|
112
|
-
Napi::Value PopArray(const uint8_t *origin, const TypeInfo *type, int16_t realign = 0);
|
|
113
|
-
|
|
114
110
|
void PopOutArguments();
|
|
115
111
|
|
|
116
112
|
void *ReserveTrampoline(const FunctionInfo *proto, Napi::Function func);
|
package/src/koffi/src/ffi.cc
CHANGED
|
@@ -271,7 +271,11 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
|
|
|
271
271
|
ThrowError<Napi::Error>(env, "Struct '%1' size is too high (max = %2)", type->name, FmtMemSize(size));
|
|
272
272
|
return env.Null();
|
|
273
273
|
}
|
|
274
|
-
|
|
274
|
+
|
|
275
|
+
bool inserted;
|
|
276
|
+
members.TrySet(member.name, &inserted);
|
|
277
|
+
|
|
278
|
+
if (!inserted) {
|
|
275
279
|
ThrowError<Napi::Error>(env, "Duplicate member '%1' in struct '%2'", member.name, type->name);
|
|
276
280
|
return env.Null();
|
|
277
281
|
}
|
|
@@ -287,9 +291,14 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
|
|
|
287
291
|
type->size = (int32_t)size;
|
|
288
292
|
|
|
289
293
|
// If the insert succeeds, we cannot fail anymore
|
|
290
|
-
if (named
|
|
291
|
-
|
|
292
|
-
|
|
294
|
+
if (named) {
|
|
295
|
+
bool inserted;
|
|
296
|
+
instance->types_map.TrySet(type->name, type, &inserted);
|
|
297
|
+
|
|
298
|
+
if (!inserted) {
|
|
299
|
+
ThrowError<Napi::Error>(env, "Duplicate type name '%1'", type->name);
|
|
300
|
+
return env.Null();
|
|
301
|
+
}
|
|
293
302
|
}
|
|
294
303
|
err_guard.Disable();
|
|
295
304
|
|
|
@@ -333,9 +342,14 @@ static Napi::Value CreateOpaqueType(const Napi::CallbackInfo &info)
|
|
|
333
342
|
type->align = 0;
|
|
334
343
|
|
|
335
344
|
// If the insert succeeds, we cannot fail anymore
|
|
336
|
-
if (named
|
|
337
|
-
|
|
338
|
-
|
|
345
|
+
if (named) {
|
|
346
|
+
bool inserted;
|
|
347
|
+
instance->types_map.TrySet(type->name, type, &inserted);
|
|
348
|
+
|
|
349
|
+
if (!inserted) {
|
|
350
|
+
ThrowError<Napi::Error>(env, "Duplicate type name '%1'", type->name);
|
|
351
|
+
return env.Null();
|
|
352
|
+
}
|
|
339
353
|
}
|
|
340
354
|
err_guard.Disable();
|
|
341
355
|
|
|
@@ -399,8 +413,11 @@ static Napi::Value CreatePointerType(const Napi::CallbackInfo &info)
|
|
|
399
413
|
memcpy((void *)copy, type, RG_SIZE(*type));
|
|
400
414
|
copy->name = DuplicateString(name.c_str(), &instance->str_alloc).ptr;
|
|
401
415
|
|
|
416
|
+
bool inserted;
|
|
417
|
+
instance->types_map.TrySet(copy->name, copy, &inserted);
|
|
418
|
+
|
|
402
419
|
// If the insert succeeds, we cannot fail anymore
|
|
403
|
-
if (!
|
|
420
|
+
if (!inserted) {
|
|
404
421
|
ThrowError<Napi::Error>(env, "Duplicate type name '%1'", copy->name);
|
|
405
422
|
return env.Null();
|
|
406
423
|
}
|
|
@@ -532,9 +549,14 @@ static Napi::Value CreateDisposableType(const Napi::CallbackInfo &info)
|
|
|
532
549
|
type->dispose_ref = Napi::Persistent(dispose_func);
|
|
533
550
|
|
|
534
551
|
// If the insert succeeds, we cannot fail anymore
|
|
535
|
-
if (named
|
|
536
|
-
|
|
537
|
-
|
|
552
|
+
if (named) {
|
|
553
|
+
bool inserted;
|
|
554
|
+
instance->types_map.TrySet(type->name, type, &inserted);
|
|
555
|
+
|
|
556
|
+
if (!inserted) {
|
|
557
|
+
ThrowError<Napi::Error>(env, "Duplicate type name '%1'", type->name);
|
|
558
|
+
return env.Null();
|
|
559
|
+
}
|
|
538
560
|
}
|
|
539
561
|
err_guard.Disable();
|
|
540
562
|
|
|
@@ -688,13 +710,13 @@ static bool ParseClassicFunction(Napi::Env env, Napi::String name, Napi::Value r
|
|
|
688
710
|
ParameterInfo param = {};
|
|
689
711
|
|
|
690
712
|
param.type = ResolveType(parameters[j], ¶m.directions);
|
|
713
|
+
|
|
691
714
|
if (!param.type)
|
|
692
715
|
return false;
|
|
693
|
-
if (!CanPassType(param.type)) {
|
|
716
|
+
if (!CanPassType(param.type, param.directions)) {
|
|
694
717
|
ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter (maybe try %1 *)", param.type->name);
|
|
695
718
|
return false;
|
|
696
719
|
}
|
|
697
|
-
|
|
698
720
|
if (func->parameters.len >= MaxParameters) {
|
|
699
721
|
ThrowError<Napi::TypeError>(env, "Functions cannot have more than %1 parameters", MaxParameters);
|
|
700
722
|
return false;
|
|
@@ -790,9 +812,10 @@ static Napi::Value CreateTypeAlias(const Napi::CallbackInfo &info)
|
|
|
790
812
|
if (!type)
|
|
791
813
|
return env.Null();
|
|
792
814
|
|
|
793
|
-
|
|
815
|
+
bool inserted;
|
|
816
|
+
instance->types_map.TrySet(alias, type, &inserted);
|
|
794
817
|
|
|
795
|
-
if (!
|
|
818
|
+
if (!inserted) {
|
|
796
819
|
ThrowError<Napi::Error>(env, "Type name '%1' already exists", alias);
|
|
797
820
|
return env.Null();
|
|
798
821
|
}
|
|
@@ -835,6 +858,40 @@ static Napi::Value GetTypeAlign(const Napi::CallbackInfo &info)
|
|
|
835
858
|
return Napi::Number::New(env, type->align);
|
|
836
859
|
}
|
|
837
860
|
|
|
861
|
+
static Napi::Value GetMemberOffset(const Napi::CallbackInfo &info)
|
|
862
|
+
{
|
|
863
|
+
Napi::Env env = info.Env();
|
|
864
|
+
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
865
|
+
|
|
866
|
+
if (info.Length() < 2) {
|
|
867
|
+
ThrowError<Napi::TypeError>(env, "Expected 2 arguments, got %1", info.Length());
|
|
868
|
+
return env.Null();
|
|
869
|
+
}
|
|
870
|
+
if (!info[1].IsString()) {
|
|
871
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for member, expected string", GetValueType(instance, info[1]));
|
|
872
|
+
return env.Null();
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
const TypeInfo *type = ResolveType(info[0]);
|
|
876
|
+
if (!type)
|
|
877
|
+
return env.Null();
|
|
878
|
+
if (type->primitive != PrimitiveKind::Record) {
|
|
879
|
+
ThrowError<Napi::TypeError>(env, "The offsetof() function can only be used with record types");
|
|
880
|
+
return env.Null();
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
std::string name = info[1].As<Napi::String>();
|
|
884
|
+
|
|
885
|
+
const RecordMember *member = std::find_if(type->members.begin(), type->members.end(),
|
|
886
|
+
[&](const RecordMember &member) { return TestStr(member.name, name.c_str()); });
|
|
887
|
+
if (member == type->members.end()) {
|
|
888
|
+
ThrowError<Napi::Error>(env, "Record type %1 does not have member '%2'", type->name, name.c_str());
|
|
889
|
+
return env.Null();
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
return Napi::Number::New(env, member->offset);
|
|
893
|
+
}
|
|
894
|
+
|
|
838
895
|
static Napi::Value GetResolvedType(const Napi::CallbackInfo &info)
|
|
839
896
|
{
|
|
840
897
|
Napi::Env env = info.Env();
|
|
@@ -915,10 +972,16 @@ static Napi::Value GetTypeDefinition(const Napi::CallbackInfo &info)
|
|
|
915
972
|
Napi::Object members = Napi::Object::New(env);
|
|
916
973
|
|
|
917
974
|
for (const RecordMember &member: type->members) {
|
|
975
|
+
Napi::Object obj = Napi::Object::New(env);
|
|
976
|
+
|
|
918
977
|
Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, (TypeInfo *)member.type);
|
|
919
978
|
SetValueTag(instance, external, &TypeInfoMarker);
|
|
920
979
|
|
|
921
|
-
|
|
980
|
+
obj.Set("name", member.name);
|
|
981
|
+
obj.Set("type", external);
|
|
982
|
+
obj.Set("offset", member.offset);
|
|
983
|
+
|
|
984
|
+
members.Set(member.name, obj);
|
|
922
985
|
}
|
|
923
986
|
|
|
924
987
|
defn.Set("members", members);
|
|
@@ -1035,13 +1098,13 @@ static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
|
|
|
1035
1098
|
ParameterInfo param = {};
|
|
1036
1099
|
|
|
1037
1100
|
param.type = ResolveType(info[i], ¶m.directions);
|
|
1101
|
+
|
|
1038
1102
|
if (RG_UNLIKELY(!param.type))
|
|
1039
1103
|
return env.Null();
|
|
1040
|
-
if (RG_UNLIKELY(!CanPassType(param.type))) {
|
|
1104
|
+
if (RG_UNLIKELY(!CanPassType(param.type, param.directions))) {
|
|
1041
1105
|
ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter (maybe try %1 *)", param.type->name);
|
|
1042
1106
|
return env.Null();
|
|
1043
1107
|
}
|
|
1044
|
-
|
|
1045
1108
|
if (RG_UNLIKELY(func.parameters.len >= MaxParameters)) {
|
|
1046
1109
|
ThrowError<Napi::TypeError>(env, "Functions cannot have more than %1 parameters", MaxParameters);
|
|
1047
1110
|
return env.Null();
|
|
@@ -1327,18 +1390,21 @@ static Napi::Value RegisterCallback(const Napi::CallbackInfo &info)
|
|
|
1327
1390
|
Napi::Env env = info.Env();
|
|
1328
1391
|
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
1329
1392
|
|
|
1330
|
-
|
|
1331
|
-
|
|
1393
|
+
bool has_recv = (info.Length() >= 3 && info[1].IsFunction());
|
|
1394
|
+
|
|
1395
|
+
if (info.Length() < 2u + has_recv) {
|
|
1396
|
+
ThrowError<Napi::TypeError>(env, "Expected 2 or 3 arguments, got %1", info.Length());
|
|
1332
1397
|
return env.Null();
|
|
1333
1398
|
}
|
|
1334
|
-
if (!info[
|
|
1335
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for func, expected function", GetValueType(instance, info[0]));
|
|
1399
|
+
if (!info[0u + has_recv].IsFunction()) {
|
|
1400
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for func, expected function", GetValueType(instance, info[0 + has_recv]));
|
|
1336
1401
|
return env.Null();
|
|
1337
1402
|
}
|
|
1338
1403
|
|
|
1339
|
-
Napi::
|
|
1404
|
+
Napi::Value recv = has_recv ? info[0] : env.Undefined();
|
|
1405
|
+
Napi::Function func = info[0u + has_recv].As<Napi::Function>();
|
|
1340
1406
|
|
|
1341
|
-
const TypeInfo *type = ResolveType(info[
|
|
1407
|
+
const TypeInfo *type = ResolveType(info[1u + has_recv]);
|
|
1342
1408
|
if (!type)
|
|
1343
1409
|
return env.Null();
|
|
1344
1410
|
if (type->primitive != PrimitiveKind::Callback) {
|
|
@@ -1346,6 +1412,7 @@ static Napi::Value RegisterCallback(const Napi::CallbackInfo &info)
|
|
|
1346
1412
|
return env.Null();
|
|
1347
1413
|
}
|
|
1348
1414
|
|
|
1415
|
+
|
|
1349
1416
|
int idx = CountTrailingZeros(~instance->registered_trampolines);
|
|
1350
1417
|
|
|
1351
1418
|
if (RG_UNLIKELY(idx >= MaxTrampolines)) {
|
|
@@ -1360,6 +1427,11 @@ static Napi::Value RegisterCallback(const Napi::CallbackInfo &info)
|
|
|
1360
1427
|
|
|
1361
1428
|
trampoline->proto = type->ref.proto;
|
|
1362
1429
|
trampoline->func.Reset(func, 1);
|
|
1430
|
+
if (!IsNullOrUndefined(recv)) {
|
|
1431
|
+
trampoline->recv.Reset(recv, 1);
|
|
1432
|
+
} else {
|
|
1433
|
+
trampoline->recv.Reset();
|
|
1434
|
+
}
|
|
1363
1435
|
trampoline->generation = -1;
|
|
1364
1436
|
|
|
1365
1437
|
void *ptr = GetTrampoline(idx, type->ref.proto);
|
|
@@ -1393,10 +1465,12 @@ static Napi::Value UnregisterCallback(const Napi::CallbackInfo &info)
|
|
|
1393
1465
|
if (!(instance->registered_trampolines & (1u << i)))
|
|
1394
1466
|
continue;
|
|
1395
1467
|
|
|
1396
|
-
|
|
1468
|
+
TrampolineInfo *trampoline = &instance->trampolines[idx];
|
|
1397
1469
|
|
|
1398
|
-
if (GetTrampoline(idx, trampoline
|
|
1470
|
+
if (GetTrampoline(idx, trampoline->proto) == ptr) {
|
|
1399
1471
|
instance->registered_trampolines &= ~(1u << i);
|
|
1472
|
+
trampoline->recv.Reset();
|
|
1473
|
+
|
|
1400
1474
|
return env.Undefined();
|
|
1401
1475
|
}
|
|
1402
1476
|
}
|
|
@@ -1459,8 +1533,9 @@ static void RegisterPrimitiveType(Napi::Env env, Napi::Object map, std::initiali
|
|
|
1459
1533
|
SetValueTag(instance, external, &TypeInfoMarker);
|
|
1460
1534
|
|
|
1461
1535
|
for (const char *name: names) {
|
|
1462
|
-
|
|
1463
|
-
|
|
1536
|
+
bool inserted;
|
|
1537
|
+
instance->types_map.TrySet(name, type, &inserted);
|
|
1538
|
+
RG_ASSERT(inserted);
|
|
1464
1539
|
|
|
1465
1540
|
if (!EndsWith(name, "*")) {
|
|
1466
1541
|
map.Set(name, external);
|
|
@@ -1546,7 +1621,8 @@ static Napi::Object InitBaseTypes(Napi::Env env)
|
|
|
1546
1621
|
RegisterPrimitiveType(env, types, {"char16_t *", "char16 *", "str16", "string16"}, PrimitiveKind::String16, RG_SIZE(void *), alignof(void *), "char16_t");
|
|
1547
1622
|
|
|
1548
1623
|
instance->void_type = instance->types_map.FindValue("void", nullptr);
|
|
1549
|
-
|
|
1624
|
+
instance->char_type = instance->types_map.FindValue("char", nullptr);
|
|
1625
|
+
instance->char16_type = instance->types_map.FindValue("char16", nullptr);
|
|
1550
1626
|
|
|
1551
1627
|
types.Freeze();
|
|
1552
1628
|
|
|
@@ -1630,6 +1706,128 @@ static Napi::Value CastValue(const Napi::CallbackInfo &info)
|
|
|
1630
1706
|
return external;
|
|
1631
1707
|
}
|
|
1632
1708
|
|
|
1709
|
+
static Napi::Value DecodeValue(const Napi::CallbackInfo &info)
|
|
1710
|
+
{
|
|
1711
|
+
Napi::Env env = info.Env();
|
|
1712
|
+
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
1713
|
+
|
|
1714
|
+
bool has_offset = (info.Length() >= 2 && info[1].IsNumber());
|
|
1715
|
+
bool has_len = (info.Length() >= 3u + has_offset && info[2u + has_offset].IsNumber());
|
|
1716
|
+
|
|
1717
|
+
if (RG_UNLIKELY(info.Length() < 2u + has_offset)) {
|
|
1718
|
+
ThrowError<Napi::TypeError>(env, "Expected %1 to 4 arguments, got %2", 2 + has_offset, info.Length());
|
|
1719
|
+
return env.Null();
|
|
1720
|
+
}
|
|
1721
|
+
if (RG_UNLIKELY(!info[0].IsExternal())) {
|
|
1722
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for variable, expected pointer (external)", GetValueType(instance, info[0]));
|
|
1723
|
+
return env.Null();
|
|
1724
|
+
}
|
|
1725
|
+
if (has_len && RG_UNLIKELY(!info[2u + has_offset].IsNumber())) {
|
|
1726
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for length, expected number", GetValueType(instance, info[2 + has_offset]));
|
|
1727
|
+
return env.Null();
|
|
1728
|
+
}
|
|
1729
|
+
|
|
1730
|
+
Napi::External<void> external = info[0].As<Napi::External<void>>();
|
|
1731
|
+
int64_t offset = has_offset ? info[1].As<Napi::Number>().Int64Value() : 0;
|
|
1732
|
+
const uint8_t *ptr = (const uint8_t *)external.Data() + offset;
|
|
1733
|
+
|
|
1734
|
+
if (!ptr)
|
|
1735
|
+
return env.Null();
|
|
1736
|
+
|
|
1737
|
+
const TypeInfo *type = ResolveType(info[1u + has_offset]);
|
|
1738
|
+
if (RG_UNLIKELY(!type))
|
|
1739
|
+
return env.Null();
|
|
1740
|
+
|
|
1741
|
+
// Used for strings and arrays, ignored otherwise
|
|
1742
|
+
int64_t len = has_len ? info[2u + has_offset].As<Napi::Number>().Int64Value() : -1;
|
|
1743
|
+
|
|
1744
|
+
#define RETURN_INT(Type, NewCall) \
|
|
1745
|
+
do { \
|
|
1746
|
+
Type v = *(Type *)ptr; \
|
|
1747
|
+
return NewCall(env, v); \
|
|
1748
|
+
} while (false)
|
|
1749
|
+
#define RETURN_INT_SWAP(Type, NewCall) \
|
|
1750
|
+
do { \
|
|
1751
|
+
Type v = ReverseBytes(*(Type *)ptr); \
|
|
1752
|
+
return NewCall(env, v); \
|
|
1753
|
+
} while (false)
|
|
1754
|
+
|
|
1755
|
+
switch (type->primitive) {
|
|
1756
|
+
case PrimitiveKind::Void: {
|
|
1757
|
+
ThrowError<Napi::TypeError>(env, "Cannot decode value of type %1", type->name);
|
|
1758
|
+
return env.Null();
|
|
1759
|
+
} break;
|
|
1760
|
+
|
|
1761
|
+
case PrimitiveKind::Bool: {
|
|
1762
|
+
bool v = *(bool *)ptr;
|
|
1763
|
+
return Napi::Boolean::New(env, v);
|
|
1764
|
+
} break;
|
|
1765
|
+
case PrimitiveKind::Int8: { RETURN_INT(int8_t, Napi::Number::New); } break;
|
|
1766
|
+
case PrimitiveKind::UInt8: { RETURN_INT(uint8_t, Napi::Number::New); } break;
|
|
1767
|
+
case PrimitiveKind::Int16: { RETURN_INT(int16_t, Napi::Number::New); } break;
|
|
1768
|
+
case PrimitiveKind::Int16S: { RETURN_INT_SWAP(int16_t, Napi::Number::New); } break;
|
|
1769
|
+
case PrimitiveKind::UInt16: { RETURN_INT(uint16_t, Napi::Number::New); } break;
|
|
1770
|
+
case PrimitiveKind::UInt16S: { RETURN_INT_SWAP(uint16_t, Napi::Number::New); } break;
|
|
1771
|
+
case PrimitiveKind::Int32: { RETURN_INT(int32_t, Napi::Number::New); } break;
|
|
1772
|
+
case PrimitiveKind::Int32S: { RETURN_INT_SWAP(int32_t, Napi::Number::New); } break;
|
|
1773
|
+
case PrimitiveKind::UInt32: { RETURN_INT(uint32_t, Napi::Number::New); } break;
|
|
1774
|
+
case PrimitiveKind::UInt32S: { RETURN_INT_SWAP(uint32_t, Napi::Number::New); } break;
|
|
1775
|
+
case PrimitiveKind::Int64: { RETURN_INT(int64_t, NewBigInt); } break;
|
|
1776
|
+
case PrimitiveKind::Int64S: { RETURN_INT_SWAP(int64_t, NewBigInt); } break;
|
|
1777
|
+
case PrimitiveKind::UInt64: { RETURN_INT(uint64_t, NewBigInt); } break;
|
|
1778
|
+
case PrimitiveKind::UInt64S: { RETURN_INT_SWAP(uint64_t, NewBigInt); } break;
|
|
1779
|
+
case PrimitiveKind::String: {
|
|
1780
|
+
if (len >= 0) {
|
|
1781
|
+
const char *str = *(const char **)ptr;
|
|
1782
|
+
return str ? Napi::String::New(env, str, len) : env.Null();
|
|
1783
|
+
} else {
|
|
1784
|
+
const char *str = *(const char **)ptr;
|
|
1785
|
+
return str ? Napi::String::New(env, str) : env.Null();
|
|
1786
|
+
}
|
|
1787
|
+
} break;
|
|
1788
|
+
case PrimitiveKind::String16: {
|
|
1789
|
+
if (len >= 0) {
|
|
1790
|
+
const char16_t *str16 = *(const char16_t **)ptr;
|
|
1791
|
+
return str16 ? Napi::String::New(env, str16, len) : env.Null();
|
|
1792
|
+
} else {
|
|
1793
|
+
const char16_t *str16 = *(const char16_t **)ptr;
|
|
1794
|
+
return str16 ? Napi::String::New(env, str16) : env.Null();
|
|
1795
|
+
}
|
|
1796
|
+
} break;
|
|
1797
|
+
case PrimitiveKind::Pointer:
|
|
1798
|
+
case PrimitiveKind::Callback: {
|
|
1799
|
+
void *ptr2 = *(void **)ptr;
|
|
1800
|
+
return ptr2 ? Napi::External<void>::New(env, ptr2, [](Napi::Env, void *) {}) : env.Null();
|
|
1801
|
+
} break;
|
|
1802
|
+
case PrimitiveKind::Array: {
|
|
1803
|
+
Napi::Value array = DecodeArray(env, ptr, type);
|
|
1804
|
+
return array;
|
|
1805
|
+
} break;
|
|
1806
|
+
case PrimitiveKind::Record: {
|
|
1807
|
+
Napi::Object obj = DecodeObject(env, ptr, type);
|
|
1808
|
+
return obj;
|
|
1809
|
+
} break;
|
|
1810
|
+
case PrimitiveKind::Float32: {
|
|
1811
|
+
float f = *(float *)ptr;
|
|
1812
|
+
return Napi::Number::New(env, f);
|
|
1813
|
+
} break;
|
|
1814
|
+
case PrimitiveKind::Float64: {
|
|
1815
|
+
double d = *(double *)ptr;
|
|
1816
|
+
return Napi::Number::New(env, d);
|
|
1817
|
+
} break;
|
|
1818
|
+
|
|
1819
|
+
case PrimitiveKind::Prototype: {
|
|
1820
|
+
ThrowError<Napi::TypeError>(env, "Cannot decode value of type %1", type->name);
|
|
1821
|
+
return env.Null();
|
|
1822
|
+
} break;
|
|
1823
|
+
}
|
|
1824
|
+
|
|
1825
|
+
#undef RETURN_BIGINT
|
|
1826
|
+
#undef RETURN_INT
|
|
1827
|
+
|
|
1828
|
+
return env.Null();
|
|
1829
|
+
}
|
|
1830
|
+
|
|
1633
1831
|
template <typename Func>
|
|
1634
1832
|
static void SetExports(Napi::Env env, Func func)
|
|
1635
1833
|
{
|
|
@@ -1645,6 +1843,7 @@ static void SetExports(Napi::Env env, Func func)
|
|
|
1645
1843
|
|
|
1646
1844
|
func("sizeof", Napi::Function::New(env, GetTypeSize));
|
|
1647
1845
|
func("alignof", Napi::Function::New(env, GetTypeAlign));
|
|
1846
|
+
func("offsetof", Napi::Function::New(env, GetMemberOffset));
|
|
1648
1847
|
func("resolve", Napi::Function::New(env, GetResolvedType));
|
|
1649
1848
|
func("introspect", Napi::Function::New(env, GetTypeDefinition));
|
|
1650
1849
|
|
|
@@ -1661,6 +1860,7 @@ static void SetExports(Napi::Env env, Func func)
|
|
|
1661
1860
|
func("unregister", Napi::Function::New(env, UnregisterCallback));
|
|
1662
1861
|
|
|
1663
1862
|
func("as", Napi::Function::New(env, CastValue));
|
|
1863
|
+
func("decode", Napi::Function::New(env, DecodeValue));
|
|
1664
1864
|
|
|
1665
1865
|
#if defined(_WIN32)
|
|
1666
1866
|
func("extension", Napi::String::New(env, ".dll"));
|
package/src/koffi/src/ffi.hh
CHANGED
|
@@ -133,7 +133,7 @@ struct RecordMember {
|
|
|
133
133
|
|
|
134
134
|
struct LibraryHolder {
|
|
135
135
|
void *module = nullptr; // HMODULE on Windows
|
|
136
|
-
mutable std::atomic_int refcount {1};
|
|
136
|
+
mutable std::atomic_int refcount { 1 };
|
|
137
137
|
|
|
138
138
|
LibraryHolder(void *module) : module(module) {}
|
|
139
139
|
~LibraryHolder();
|
|
@@ -192,7 +192,7 @@ struct ValueCast {
|
|
|
192
192
|
|
|
193
193
|
// Also used for callbacks, even though many members are not used in this case
|
|
194
194
|
struct FunctionInfo {
|
|
195
|
-
mutable std::atomic_int refcount {1};
|
|
195
|
+
mutable std::atomic_int refcount { 1 };
|
|
196
196
|
|
|
197
197
|
const char *name;
|
|
198
198
|
const char *decorated_name; // Only set for some platforms/calling conventions
|
|
@@ -236,6 +236,7 @@ struct InstanceMemory {
|
|
|
236
236
|
struct TrampolineInfo {
|
|
237
237
|
const FunctionInfo *proto;
|
|
238
238
|
Napi::FunctionReference func;
|
|
239
|
+
Napi::Reference<Napi::Value> recv;
|
|
239
240
|
|
|
240
241
|
int32_t generation;
|
|
241
242
|
};
|
|
@@ -249,7 +250,10 @@ struct InstanceData {
|
|
|
249
250
|
|
|
250
251
|
bool debug;
|
|
251
252
|
uint64_t tag_lower;
|
|
253
|
+
|
|
252
254
|
const TypeInfo *void_type;
|
|
255
|
+
const TypeInfo *char_type;
|
|
256
|
+
const TypeInfo *char16_type;
|
|
253
257
|
|
|
254
258
|
LocalArray<InstanceMemory *, 9> memories;
|
|
255
259
|
int temporaries = 0;
|
package/src/koffi/src/parser.cc
CHANGED
|
@@ -65,18 +65,11 @@ bool PrototypeParser::Parse(const char *str, FunctionInfo *out_func)
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
param.type = ParseType();
|
|
68
|
-
if (!CanPassType(param.type)) {
|
|
69
|
-
MarkError("Type %1 cannot be used as a parameter (maybe try %1 *)", param.type->name);
|
|
70
|
-
return false;
|
|
71
|
-
}
|
|
72
68
|
|
|
73
|
-
if ((param.
|
|
74
|
-
MarkError("
|
|
69
|
+
if (!CanPassType(param.type, param.directions)) {
|
|
70
|
+
MarkError("Type %1 cannot be used as a parameter (maybe try %1 *)", param.type->name);
|
|
75
71
|
return false;
|
|
76
72
|
}
|
|
77
|
-
|
|
78
|
-
offset += (offset < tokens.len && IsIdentifier(tokens[offset]));
|
|
79
|
-
|
|
80
73
|
if (out_func->parameters.len >= MaxParameters) {
|
|
81
74
|
MarkError("Functions cannot have more than %1 parameters", MaxParameters);
|
|
82
75
|
return false;
|
|
@@ -90,6 +83,7 @@ bool PrototypeParser::Parse(const char *str, FunctionInfo *out_func)
|
|
|
90
83
|
|
|
91
84
|
out_func->parameters.Append(param);
|
|
92
85
|
|
|
86
|
+
offset += (offset < tokens.len && IsIdentifier(tokens[offset]));
|
|
93
87
|
if (offset >= tokens.len || tokens[offset] != ",")
|
|
94
88
|
break;
|
|
95
89
|
offset++;
|