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.
Files changed (65) hide show
  1. package/ChangeLog.md +21 -1
  2. package/doc/Makefile +1 -1
  3. package/doc/callbacks.md +175 -0
  4. package/doc/changes.md +2 -3
  5. package/doc/conf.py +29 -6
  6. package/doc/functions.md +39 -124
  7. package/doc/index.rst +1 -0
  8. package/doc/make.bat +1 -1
  9. package/doc/types.md +36 -9
  10. package/package.json +2 -2
  11. package/src/core/libcc/libcc.cc +89 -27
  12. package/src/core/libcc/libcc.hh +74 -39
  13. package/src/koffi/build/2.2.1/koffi_darwin_arm64.tar.gz +0 -0
  14. package/src/koffi/build/2.2.1/koffi_darwin_x64.tar.gz +0 -0
  15. package/src/koffi/build/2.2.1/koffi_freebsd_arm64.tar.gz +0 -0
  16. package/src/koffi/build/2.2.1/koffi_freebsd_ia32.tar.gz +0 -0
  17. package/src/koffi/build/2.2.1/koffi_freebsd_x64.tar.gz +0 -0
  18. package/src/koffi/build/2.2.1/koffi_linux_arm32hf.tar.gz +0 -0
  19. package/src/koffi/build/2.2.1/koffi_linux_arm64.tar.gz +0 -0
  20. package/src/koffi/build/2.2.1/koffi_linux_ia32.tar.gz +0 -0
  21. package/src/koffi/build/2.2.1/koffi_linux_riscv64hf64.tar.gz +0 -0
  22. package/src/koffi/build/2.2.1/koffi_linux_x64.tar.gz +0 -0
  23. package/src/koffi/build/2.2.1/koffi_openbsd_ia32.tar.gz +0 -0
  24. package/src/koffi/build/2.2.1/koffi_openbsd_x64.tar.gz +0 -0
  25. package/src/koffi/build/2.2.1/koffi_win32_arm64.tar.gz +0 -0
  26. package/src/koffi/build/2.2.1/koffi_win32_ia32.tar.gz +0 -0
  27. package/src/koffi/build/2.2.1/koffi_win32_x64.tar.gz +0 -0
  28. package/src/koffi/qemu/qemu.js +3 -1
  29. package/src/koffi/src/abi_arm32.cc +26 -23
  30. package/src/koffi/src/abi_arm64.cc +25 -22
  31. package/src/koffi/src/abi_riscv64.cc +21 -18
  32. package/src/koffi/src/abi_x64_sysv.cc +20 -17
  33. package/src/koffi/src/abi_x64_win.cc +19 -16
  34. package/src/koffi/src/abi_x86.cc +23 -20
  35. package/src/koffi/src/call.cc +222 -607
  36. package/src/koffi/src/call.hh +7 -11
  37. package/src/koffi/src/ffi.cc +229 -29
  38. package/src/koffi/src/ffi.hh +6 -2
  39. package/src/koffi/src/parser.cc +3 -9
  40. package/src/koffi/src/util.cc +546 -8
  41. package/src/koffi/src/util.hh +8 -2
  42. package/src/koffi/test/CMakeLists.txt +3 -3
  43. package/src/koffi/test/callbacks.js +89 -0
  44. package/src/koffi/test/misc.c +78 -0
  45. package/src/koffi/test/raylib.js +2 -2
  46. package/src/koffi/test/sqlite.js +1 -1
  47. package/src/koffi/test/sync.js +28 -6
  48. package/vendor/brotli/c/common/platform.h +2 -0
  49. package/vendor/sqlite3mc/sqlite3.c +243532 -0
  50. package/vendor/sqlite3mc/sqlite3.h +12887 -0
  51. package/src/koffi/build/2.1.5/koffi_darwin_arm64.tar.gz +0 -0
  52. package/src/koffi/build/2.1.5/koffi_darwin_x64.tar.gz +0 -0
  53. package/src/koffi/build/2.1.5/koffi_freebsd_arm64.tar.gz +0 -0
  54. package/src/koffi/build/2.1.5/koffi_freebsd_ia32.tar.gz +0 -0
  55. package/src/koffi/build/2.1.5/koffi_freebsd_x64.tar.gz +0 -0
  56. package/src/koffi/build/2.1.5/koffi_linux_arm32hf.tar.gz +0 -0
  57. package/src/koffi/build/2.1.5/koffi_linux_arm64.tar.gz +0 -0
  58. package/src/koffi/build/2.1.5/koffi_linux_ia32.tar.gz +0 -0
  59. package/src/koffi/build/2.1.5/koffi_linux_riscv64hf64.tar.gz +0 -0
  60. package/src/koffi/build/2.1.5/koffi_linux_x64.tar.gz +0 -0
  61. package/src/koffi/build/2.1.5/koffi_openbsd_ia32.tar.gz +0 -0
  62. package/src/koffi/build/2.1.5/koffi_openbsd_x64.tar.gz +0 -0
  63. package/src/koffi/build/2.1.5/koffi_win32_arm64.tar.gz +0 -0
  64. package/src/koffi/build/2.1.5/koffi_win32_ia32.tar.gz +0 -0
  65. package/src/koffi/build/2.1.5/koffi_win32_x64.tar.gz +0 -0
@@ -65,7 +65,7 @@ class alignas(8) CallData {
65
65
  } result;
66
66
  uint8_t *return_ptr = nullptr;
67
67
 
68
- LinkedAllocator call_alloc;
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
- bool PushString16(Napi::Value value, const char16_t **out_str16);
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 *ref, uint8_t *origin, int16_t realign = 0);
104
- bool PushTypedArray(Napi::TypedArray array, Size len, const TypeInfo *ref, uint8_t *origin, int16_t realign = 0);
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);
@@ -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
- if (!members.TrySet(member.name).second) {
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 && !instance->types_map.TrySet(type->name, type).second) {
291
- ThrowError<Napi::Error>(env, "Duplicate type name '%1'", type->name);
292
- return env.Null();
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 && !instance->types_map.TrySet(type->name, type).second) {
337
- ThrowError<Napi::Error>(env, "Duplicate type name '%1'", type->name);
338
- return env.Null();
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 (!instance->types_map.TrySet(copy->name, copy).second) {
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 && !instance->types_map.TrySet(type->name, type).second) {
536
- ThrowError<Napi::Error>(env, "Duplicate type name '%1'", type->name);
537
- return env.Null();
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], &param.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
- std::pair<const TypeInfo **, bool> ret = instance->types_map.TrySet(alias, type);
815
+ bool inserted;
816
+ instance->types_map.TrySet(alias, type, &inserted);
794
817
 
795
- if (!ret.second) {
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
- members.Set(member.name, external);
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], &param.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
- if (info.Length() < 2) {
1331
- ThrowError<Napi::TypeError>(env, "Expected 2 arguments, got %1", info.Length());
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[0].IsFunction()) {
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::Function func = info[0].As<Napi::Function>();
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[1]);
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
- const TrampolineInfo &trampoline = instance->trampolines[idx];
1468
+ TrampolineInfo *trampoline = &instance->trampolines[idx];
1397
1469
 
1398
- if (GetTrampoline(idx, trampoline.proto) == ptr) {
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
- std::pair<const TypeInfo **, bool> ret = instance->types_map.TrySet(name, type);
1463
- RG_ASSERT(ret.second);
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
- RG_ASSERT(instance->void_type);
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"));
@@ -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;
@@ -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.directions & 2) && param.type->primitive != PrimitiveKind::Pointer) {
74
- MarkError("Only pointers can be used for output parameters");
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++;