koffi 3.0.1 → 3.1.0

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 (50) hide show
  1. package/CHANGELOG.md +32 -3
  2. package/cnoke.cjs +2 -2
  3. package/doc/benchmarks.md +1 -1
  4. package/doc/callbacks.md +7 -26
  5. package/doc/{input.md → composites.md} +161 -147
  6. package/doc/contribute.md +3 -2
  7. package/doc/index.md +0 -14
  8. package/doc/{functions.md → load.md} +54 -113
  9. package/doc/migration.md +4 -7
  10. package/doc/misc.md +0 -103
  11. package/doc/output.md +5 -11
  12. package/doc/pointers.md +76 -17
  13. package/doc/primitives.md +151 -0
  14. package/doc/start.md +3 -13
  15. package/doc/types.md +88 -0
  16. package/doc/unions.md +0 -186
  17. package/doc/values.md +134 -0
  18. package/index.d.ts +375 -308
  19. package/lib/native/base/base.cc +66 -24
  20. package/lib/native/base/base.hh +55 -153
  21. package/package.json +16 -16
  22. package/src/koffi/CMakeLists.txt +20 -17
  23. package/src/koffi/index.cjs +30 -111
  24. package/src/koffi/index.js +22 -96
  25. package/src/koffi/indirect.cjs +30 -111
  26. package/src/koffi/indirect.js +24 -24
  27. package/src/koffi/src/abi/arm64.cc +48 -62
  28. package/src/koffi/src/abi/riscv64.cc +39 -57
  29. package/src/koffi/src/abi/x64sysv.cc +39 -57
  30. package/src/koffi/src/abi/x64win.cc +48 -65
  31. package/src/koffi/src/abi/x86.cc +47 -59
  32. package/src/koffi/src/call.cc +426 -209
  33. package/src/koffi/src/call.hh +7 -11
  34. package/src/koffi/src/ffi.cc +534 -303
  35. package/src/koffi/src/ffi.hh +71 -15
  36. package/src/koffi/src/parser.cc +5 -3
  37. package/src/koffi/src/parser.hh +2 -2
  38. package/src/koffi/src/static.cjs +122 -0
  39. package/src/koffi/src/static.js +125 -0
  40. package/src/koffi/src/type.cc +725 -0
  41. package/src/koffi/src/type.hh +71 -0
  42. package/src/koffi/src/util.cc +117 -1202
  43. package/src/koffi/src/util.hh +158 -156
  44. package/src/koffi/src/uv.cc +17 -11
  45. package/src/koffi/src/uv.hh +2 -1
  46. package/vendor/node-addon-api/README.md +1 -1
  47. package/vendor/node-addon-api/napi-inl.h +213 -35
  48. package/vendor/node-addon-api/napi.h +118 -7
  49. package/doc/variables.md +0 -102
  50. package/indirect.d.ts +0 -322
@@ -5,6 +5,7 @@
5
5
  #include "ffi.hh"
6
6
  #include "call.hh"
7
7
  #include "parser.hh"
8
+ #include "type.hh"
8
9
  #include "util.hh"
9
10
  #include "uv.hh"
10
11
  #if defined(_WIN32)
@@ -35,23 +36,28 @@
35
36
 
36
37
  namespace K {
37
38
 
39
+ // Value does not matter, the tag system uses memory addresses
40
+ const napi_type_tag LibraryHandleMarker = { 0xdb9b066e6f700474, 0x0aecd7e4c63fbda9 };
41
+ const napi_type_tag TypeObjectMarker = { 0x1cc449675b294374, 0xbb13a50e97dcb017 };
42
+ const napi_type_tag DirectionMarker = { 0xf9c306238b480580, 0xc2e168524a0823f5 };
43
+ const napi_type_tag UnionValueMarker = { 0x5eaf2245526a4c7d, 0x8c86c9ee2b96ffc8 };
44
+ const napi_type_tag CastMarker = { 0x77f459614a0a412f, 0x80b3dda1341dc8df };
45
+
38
46
  SharedData shared;
39
47
 
40
48
  // Some Node-API functions are loaded dynamically to work around bugs or because they are recent
49
+ napi_status (NAPI_CDECL *node_api_delete_reference)(node_api_basic_env env, napi_ref ref);
41
50
  napi_status (NAPI_CDECL *node_api_get_buffer_info)(napi_env env, napi_value value, void **data, size_t *length);
42
51
  napi_status (NAPI_CDECL *node_api_create_property_key_utf8)(napi_env env, const char* str, size_t length, napi_value* result);
43
52
  napi_status (NAPI_CDECL *node_api_post_finalizer)(node_api_basic_env env, napi_finalize finalize_cb, void* finalize_data, void* finalize_hint);
44
53
  napi_status (NAPI_CDECL *node_api_create_object_with_properties)(napi_env env, napi_value prototype_or_null, const napi_value *property_names,
45
54
  const napi_value *property_values, size_t property_count, napi_value *result);
46
- napi_value (*translate_zero_call)(napi_env env, napi_callback_info info);
47
55
 
48
- static bool ChangeSize(const char *name, Napi::Value value, Size min_size, Size max_size, Size *out_size)
56
+ static bool ChangeSize(InstanceData *instance, const char *name, Napi::Value value, Size min_size, Size max_size, Size *out_size)
49
57
  {
50
- Napi::Env env = value.Env();
58
+ Napi::Env env = instance->env;
51
59
 
52
60
  if (!value.IsNumber()) {
53
- InstanceData *instance = env.GetInstanceData<InstanceData>();
54
-
55
61
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for '%2', expected number", GetValueType(instance, value), name);
56
62
  return false;
57
63
  }
@@ -67,21 +73,19 @@ static bool ChangeSize(const char *name, Napi::Value value, Size min_size, Size
67
73
  return true;
68
74
  }
69
75
 
70
- static bool ChangeMemorySize(const char *name, Napi::Value value, Size *out_size)
76
+ static bool ChangeMemorySize(InstanceData *instance, const char *name, Napi::Value value, Size *out_size)
71
77
  {
72
78
  const Size MinSize = Kibibytes(1);
73
79
  const Size MaxSize = Mebibytes(16);
74
80
 
75
- return ChangeSize(name, value, MinSize, MaxSize, out_size);
81
+ return ChangeSize(instance, name, value, MinSize, MaxSize, out_size);
76
82
  }
77
83
 
78
- static bool ChangeAsyncLimit(const char *name, Napi::Value value, int max, int *out_limit)
84
+ static bool ChangeAsyncLimit(InstanceData *instance, const char *name, Napi::Value value, int max, int *out_limit)
79
85
  {
80
86
  Napi::Env env = value.Env();
81
87
 
82
88
  if (!value.IsNumber()) {
83
- InstanceData *instance = env.GetInstanceData<InstanceData>();
84
-
85
89
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for '%2', expected number", GetValueType(instance, value), name);
86
90
  return false;
87
91
  }
@@ -100,7 +104,7 @@ static bool ChangeAsyncLimit(const char *name, Napi::Value value, int max, int *
100
104
  static Napi::Value GetSetConfig(const Napi::CallbackInfo &info)
101
105
  {
102
106
  Napi::Env env = info.Env();
103
- InstanceData *instance = env.GetInstanceData<InstanceData>();
107
+ InstanceData *instance = (InstanceData *)info.Data();
104
108
 
105
109
  if (info.Length()) {
106
110
  if (instance->memories.len) {
@@ -124,25 +128,25 @@ static Napi::Value GetSetConfig(const Napi::CallbackInfo &info)
124
128
  Napi::Value value = obj[key];
125
129
 
126
130
  if (key == "sync_stack_size") {
127
- if (!ChangeMemorySize(key.c_str(), value, &new_config.sync_stack_size))
131
+ if (!ChangeMemorySize(instance, key.c_str(), value, &new_config.sync_stack_size))
128
132
  return env.Null();
129
133
  } else if (key == "sync_heap_size") {
130
- if (!ChangeMemorySize(key.c_str(), value, &new_config.sync_heap_size))
134
+ if (!ChangeMemorySize(instance, key.c_str(), value, &new_config.sync_heap_size))
131
135
  return env.Null();
132
136
  } else if (key == "async_stack_size") {
133
- if (!ChangeMemorySize(key.c_str(), value, &new_config.async_stack_size))
137
+ if (!ChangeMemorySize(instance, key.c_str(), value, &new_config.async_stack_size))
134
138
  return env.Null();
135
139
  } else if (key == "async_heap_size") {
136
- if (!ChangeMemorySize(key.c_str(), value, &new_config.async_heap_size))
140
+ if (!ChangeMemorySize(instance, key.c_str(), value, &new_config.async_heap_size))
137
141
  return env.Null();
138
142
  } else if (key == "resident_async_pools") {
139
- if (!ChangeAsyncLimit(key.c_str(), value, K_LEN(instance->memories.data) - 1, &new_config.resident_async_pools))
143
+ if (!ChangeAsyncLimit(instance, key.c_str(), value, K_LEN(instance->memories.data) - 1, &new_config.resident_async_pools))
140
144
  return env.Null();
141
145
  } else if (key == "max_async_calls") {
142
- if (!ChangeAsyncLimit(key.c_str(), value, MaxAsyncCalls, &max_async_calls))
146
+ if (!ChangeAsyncLimit(instance, key.c_str(), value, MaxAsyncCalls, &max_async_calls))
143
147
  return env.Null();
144
148
  } else if (key == "max_type_size") {
145
- if (!ChangeSize(key.c_str(), value, 32, Mebibytes(512), &new_config.max_type_size))
149
+ if (!ChangeSize(instance, key.c_str(), value, 32, Mebibytes(512), &new_config.max_type_size))
146
150
  return env.Null();
147
151
  } else {
148
152
  ThrowError<Napi::Error>(env, "Unexpected config member '%1'", key.c_str());
@@ -175,7 +179,7 @@ static Napi::Value GetSetConfig(const Napi::CallbackInfo &info)
175
179
  static Napi::Value GetStats(const Napi::CallbackInfo &info)
176
180
  {
177
181
  Napi::Env env = info.Env();
178
- InstanceData *instance = env.GetInstanceData<InstanceData>();
182
+ InstanceData *instance = (InstanceData *)info.Data();
179
183
 
180
184
  Napi::Object obj = Napi::Object::New(env);
181
185
 
@@ -228,9 +232,9 @@ static bool FinalizeCompositeType(Napi::Env env, TypeInfo *type, PrimitiveKind p
228
232
  if (node_api_create_property_key_utf8) {
229
233
  for (RecordMember &member: type->members) {
230
234
  napi_value key = nullptr;
231
- node_api_create_property_key_utf8(env, member.name, NAPI_AUTO_LENGTH, &key);
232
235
 
233
- napi_create_reference(env, key, 1, &member.key);
236
+ NAPI_OK(node_api_create_property_key_utf8(env, member.name, NAPI_AUTO_LENGTH, &key));
237
+ NAPI_OK(napi_create_reference(env, key, 1, &member.key));
234
238
  }
235
239
  }
236
240
 
@@ -247,7 +251,7 @@ static bool FinalizeCompositeType(Napi::Env env, TypeInfo *type, PrimitiveKind p
247
251
  static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
248
252
  {
249
253
  Napi::Env env = info.Env();
250
- InstanceData *instance = env.GetInstanceData<InstanceData>();
254
+ InstanceData *instance = (InstanceData *)info.Data();
251
255
 
252
256
  if (info.Length() < 1) {
253
257
  ThrowError<Napi::TypeError>(env, "Expected 1 or 2 arguments, got %1", info.Length());
@@ -299,11 +303,12 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
299
303
  replace = external.Data();
300
304
  #else
301
305
  TypeObject *defn = nullptr;
302
- napi_unwrap(env, name, (void **)&defn);
306
+ NAPI_OK(napi_unwrap(env, name, (void **)&defn));
303
307
 
304
308
  replace = (TypeInfo *)defn->GetType();
305
309
  #endif
306
310
 
311
+ type->instance = instance;
307
312
  type->name = replace->name;
308
313
 
309
314
  if (replace->primitive != PrimitiveKind::Void || replace == instance->void_type) {
@@ -311,11 +316,13 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
311
316
  return env.Null();
312
317
  }
313
318
  } else if (named) {
319
+ type->instance = instance;
314
320
  type->name = DuplicateString(name.Utf8Value().c_str(), &instance->str_alloc).ptr;
315
321
 
316
322
  if (!MapType(env, instance, type, type->name))
317
323
  return env.Null();
318
324
  } else {
325
+ type->instance = instance;
319
326
  type->name = Fmt(&instance->str_alloc, "<anonymous_%1>", instance->types.count).ptr;
320
327
  }
321
328
 
@@ -353,7 +360,7 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
353
360
  align = (int16_t)align64;
354
361
  }
355
362
 
356
- member.type = ResolveType(value);
363
+ member.type = ResolveType(instance, value);
357
364
  if (!member.type)
358
365
  return env.Null();
359
366
  if (!CanStoreType(member.type)) {
@@ -425,11 +432,12 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
425
432
  err_guard.Disable();
426
433
 
427
434
  if (replace) {
428
- std::swap(*type, *replace);
435
+ *replace = std::move(*type);
429
436
  type = replace;
430
437
  }
431
438
 
432
- return WrapType(env, type);
439
+ napi_value wrapper = WrapType(instance, type);
440
+ return Napi::Value(env, wrapper);
433
441
  }
434
442
 
435
443
  static Napi::Value CreatePaddedStructType(const Napi::CallbackInfo &info)
@@ -445,7 +453,7 @@ static Napi::Value CreatePackedStructType(const Napi::CallbackInfo &info)
445
453
  static Napi::Value CreateUnionType(const Napi::CallbackInfo &info)
446
454
  {
447
455
  Napi::Env env = info.Env();
448
- InstanceData *instance = env.GetInstanceData<InstanceData>();
456
+ InstanceData *instance = (InstanceData *)info.Data();
449
457
 
450
458
  if (info.Length() < 1) {
451
459
  ThrowError<Napi::TypeError>(env, "Expected 1 or 2 arguments, got %1", info.Length());
@@ -497,11 +505,12 @@ static Napi::Value CreateUnionType(const Napi::CallbackInfo &info)
497
505
  replace = external.Data();
498
506
  #else
499
507
  TypeObject *defn = nullptr;
500
- napi_unwrap(env, name, (void **)&defn);
508
+ NAPI_OK(napi_unwrap(env, name, (void **)&defn));
501
509
 
502
510
  replace = (TypeInfo *)defn->GetType();
503
511
  #endif
504
512
 
513
+ type->instance = instance;
505
514
  type->name = replace->name;
506
515
 
507
516
  if (replace->primitive != PrimitiveKind::Void || replace == instance->void_type) {
@@ -509,11 +518,13 @@ static Napi::Value CreateUnionType(const Napi::CallbackInfo &info)
509
518
  return env.Null();
510
519
  }
511
520
  } else if (named) {
521
+ type->instance = instance;
512
522
  type->name = DuplicateString(name.Utf8Value().c_str(), &instance->str_alloc).ptr;
513
523
 
514
524
  if (!MapType(env, instance, type, type->name))
515
525
  return env.Null();
516
526
  } else {
527
+ type->instance = instance;
517
528
  type->name = Fmt(&instance->str_alloc, "<anonymous_%1>", instance->types.count).ptr;
518
529
  }
519
530
 
@@ -551,7 +562,7 @@ static Napi::Value CreateUnionType(const Napi::CallbackInfo &info)
551
562
  align = (int16_t)align64;
552
563
  }
553
564
 
554
- member.type = ResolveType(value);
565
+ member.type = ResolveType(instance, value);
555
566
  if (!member.type)
556
567
  return env.Null();
557
568
  if (!CanStoreType(member.type)) {
@@ -592,19 +603,22 @@ static Napi::Value CreateUnionType(const Napi::CallbackInfo &info)
592
603
  return env.Null();
593
604
  err_guard.Disable();
594
605
 
595
- type->construct = Napi::Persistent(UnionValue::InitClass(env, type));
606
+ Napi::Object construct = UnionValue::InitClass(instance, type);
607
+ NAPI_OK(napi_create_reference(env, construct, 1, &type->construct));
596
608
 
597
609
  if (replace) {
598
- std::swap(*type, *replace);
610
+ *replace = std::move(*type);
599
611
  type = replace;
600
612
  }
601
613
 
602
- return WrapType(env, type);
614
+ napi_value wrapper = WrapType(instance, type);
615
+ return Napi::Value(env, wrapper);
603
616
  }
604
617
 
605
618
  Napi::Value InstantiateUnion(const Napi::CallbackInfo &info)
606
619
  {
607
620
  Napi::Env env = info.Env();
621
+ InstanceData *instance = (InstanceData *)info.Data();
608
622
 
609
623
  if (!info.IsConstructCall()) {
610
624
  ThrowError<Napi::TypeError>(env, "This function is a constructor and must be called with new");
@@ -615,7 +629,7 @@ Napi::Value InstantiateUnion(const Napi::CallbackInfo &info)
615
629
  return env.Null();
616
630
  }
617
631
 
618
- const TypeInfo *type = ResolveType(info[0]);
632
+ const TypeInfo *type = ResolveType(instance, info[0]);
619
633
  if (!type)
620
634
  return env.Null();
621
635
  if (type->primitive != PrimitiveKind::Union) {
@@ -623,7 +637,15 @@ Napi::Value InstantiateUnion(const Napi::CallbackInfo &info)
623
637
  return env.Null();
624
638
  }
625
639
 
626
- Napi::Object wrapper = type->construct.New({}).As<Napi::Object>();
640
+ Napi::Function construct;
641
+ {
642
+ napi_value value;
643
+ NAPI_OK(napi_get_reference_value(env, type->construct, &value));
644
+
645
+ construct = Napi::Function(env, value);
646
+ }
647
+
648
+ Napi::Object wrapper = construct.New({}).As<Napi::Object>();
627
649
  SetValueTag(env, wrapper, &UnionValueMarker);
628
650
 
629
651
  return wrapper;
@@ -632,7 +654,7 @@ Napi::Value InstantiateUnion(const Napi::CallbackInfo &info)
632
654
  static Napi::Value CreateOpaqueType(const Napi::CallbackInfo &info)
633
655
  {
634
656
  Napi::Env env = info.Env();
635
- InstanceData *instance = env.GetInstanceData<InstanceData>();
657
+ InstanceData *instance = (InstanceData *)info.Data();
636
658
 
637
659
  bool named = (info.Length() >= 1) && !IsNullOrUndefined(env, info[0]);
638
660
 
@@ -646,6 +668,7 @@ static Napi::Value CreateOpaqueType(const Napi::CallbackInfo &info)
646
668
  TypeInfo *type = instance->types.AppendDefault();
647
669
  K_DEFER_N(err_guard) { instance->types.RemoveLast(1); };
648
670
 
671
+ type->instance = instance;
649
672
  type->name = named ? DuplicateString(name.Utf8Value().c_str(), &instance->str_alloc).ptr
650
673
  : Fmt(&instance->str_alloc, "<anonymous_%1>", instance->types.count).ptr;
651
674
 
@@ -658,13 +681,14 @@ static Napi::Value CreateOpaqueType(const Napi::CallbackInfo &info)
658
681
  return env.Null();
659
682
  err_guard.Disable();
660
683
 
661
- return WrapType(env, type);
684
+ napi_value wrapper = WrapType(instance, type);
685
+ return Napi::Value(env, wrapper);
662
686
  }
663
687
 
664
688
  static Napi::Value CreatePointerType(const Napi::CallbackInfo &info)
665
689
  {
666
690
  Napi::Env env = info.Env();
667
- InstanceData *instance = env.GetInstanceData<InstanceData>();
691
+ InstanceData *instance = (InstanceData *)info.Data();
668
692
 
669
693
  if (info.Length() < 1) {
670
694
  ThrowError<Napi::TypeError>(env, "Expected 1 to 3 arguments, got %1", info.Length());
@@ -681,7 +705,7 @@ static Napi::Value CreatePointerType(const Napi::CallbackInfo &info)
681
705
 
682
706
  std::string name = named ? info[0].As<Napi::String>() : std::string();
683
707
 
684
- const TypeInfo *ref = ResolveType(info[skip]);
708
+ const TypeInfo *ref = ResolveType(instance, info[skip]);
685
709
  if (!ref)
686
710
  return env.Null();
687
711
 
@@ -713,7 +737,7 @@ static Napi::Value CreatePointerType(const Napi::CallbackInfo &info)
713
737
 
714
738
  memcpy((void *)copy, type, K_SIZE(*type));
715
739
  copy->name = named ? DuplicateString(name.c_str(), &instance->str_alloc).ptr : copy->name;
716
- memset((void *)&copy->defn, 0, K_SIZE(copy->defn));
740
+ copy->defn = nullptr;
717
741
 
718
742
  static_assert(!std::is_polymorphic_v<Napi::ObjectReference>);
719
743
 
@@ -730,7 +754,8 @@ static Napi::Value CreatePointerType(const Napi::CallbackInfo &info)
730
754
  type = copy;
731
755
  }
732
756
 
733
- return WrapType(env, type);
757
+ napi_value wrapper = WrapType(instance, type);
758
+ return Napi::Value(env, wrapper);
734
759
  }
735
760
 
736
761
  static Napi::Value EncodePointerDirection(const Napi::CallbackInfo &info, int directions)
@@ -738,13 +763,14 @@ static Napi::Value EncodePointerDirection(const Napi::CallbackInfo &info, int di
738
763
  K_ASSERT(directions >= 1 && directions <= 3);
739
764
 
740
765
  Napi::Env env = info.Env();
766
+ InstanceData *instance = (InstanceData *)info.Data();
741
767
 
742
768
  if (info.Length() < 1) {
743
769
  ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
744
770
  return env.Null();
745
771
  }
746
772
 
747
- const TypeInfo *type = ResolveType(info[0]);
773
+ const TypeInfo *type = ResolveType(instance, info[0]);
748
774
  if (!type)
749
775
  return env.Null();
750
776
 
@@ -783,7 +809,7 @@ static Napi::Value MarkInOut(const Napi::CallbackInfo &info)
783
809
  static Napi::Value CreateDisposableType(const Napi::CallbackInfo &info)
784
810
  {
785
811
  Napi::Env env = info.Env();
786
- InstanceData *instance = env.GetInstanceData<InstanceData>();
812
+ InstanceData *instance = (InstanceData *)info.Data();
787
813
 
788
814
  if (info.Length() < 1) {
789
815
  ThrowError<Napi::TypeError>(env, "Expected 1 or 2 arguments, got %1", info.Length());
@@ -800,7 +826,7 @@ static Napi::Value CreateDisposableType(const Napi::CallbackInfo &info)
800
826
 
801
827
  Napi::String name = info[0].As<Napi::String>();
802
828
 
803
- const TypeInfo *src = ResolveType(info[skip]);
829
+ const TypeInfo *src = ResolveType(instance, info[skip]);
804
830
  if (!src)
805
831
  return env.Null();
806
832
  if (src->primitive != PrimitiveKind::Pointer &&
@@ -825,23 +851,21 @@ static Napi::Value CreateDisposableType(const Napi::CallbackInfo &info)
825
851
  return env.Null();
826
852
  }
827
853
 
828
- dispose = [](Napi::Env env, const TypeInfo *type, const void *ptr) {
829
- InstanceData *instance = env.GetInstanceData<InstanceData>();
830
- const Napi::FunctionReference &ref = type->dispose_ref;
854
+ dispose = [](InstanceData *instance, const TypeInfo *type, const void *ptr) {
855
+ Napi::Env env = instance->env;
831
856
 
832
- Napi::Value p = WrapPointer(env, type->ref.type, (void *)ptr);
857
+ napi_value func;
858
+ NAPI_OK(napi_get_reference_value(env, type->dispose_ref, &func));
833
859
 
834
860
  napi_value self = env.Null();
835
- napi_value args[] = { p };
861
+ napi_value wrapper = WrapPointer(env, type->ref.type, (void *)ptr);
836
862
 
837
- ref.Call(self, K_LEN(args), args);
863
+ NAPI_OK(napi_call_function(env, self, func, 1, &wrapper, nullptr));
838
864
  instance->stats.disposed++;
839
865
  };
840
866
  dispose_func = func;
841
867
  } else {
842
- dispose = [](Napi::Env env, const TypeInfo *, const void *ptr) {
843
- InstanceData *instance = env.GetInstanceData<InstanceData>();
844
-
868
+ dispose = [](InstanceData *instance, const TypeInfo *, const void *ptr) {
845
869
  free((void *)ptr);
846
870
  instance->stats.disposed++;
847
871
  };
@@ -851,9 +875,8 @@ static Napi::Value CreateDisposableType(const Napi::CallbackInfo &info)
851
875
  K_DEFER_N(err_guard) { instance->types.RemoveLast(1); };
852
876
 
853
877
  memcpy((void *)type, (const void *)src, K_SIZE(*src));
854
- type->members.allocator = GetNullAllocator();
855
- type->members.allocator = GetNullAllocator();
856
- memset((void *)&type->defn, 0, K_SIZE(type->defn));
878
+ type->defn = nullptr;
879
+ K_ASSERT(!type->members.len);
857
880
 
858
881
  static_assert(!std::is_polymorphic_v<Napi::ObjectReference>);
859
882
 
@@ -861,7 +884,7 @@ static Napi::Value CreateDisposableType(const Napi::CallbackInfo &info)
861
884
  : Fmt(&instance->str_alloc, "<anonymous_%1>", instance->types.count).ptr;
862
885
 
863
886
  type->dispose = dispose;
864
- type->dispose_ref = Napi::Persistent(dispose_func);
887
+ NAPI_OK(napi_create_reference(env, dispose_func, 1, &type->dispose_ref));
865
888
 
866
889
  // If the insert succeeds, we cannot fail anymore
867
890
  if (named) {
@@ -875,13 +898,14 @@ static Napi::Value CreateDisposableType(const Napi::CallbackInfo &info)
875
898
  }
876
899
  err_guard.Disable();
877
900
 
878
- return WrapType(env, type);
901
+ napi_value wrapper = WrapType(instance, type);
902
+ return Napi::Value(env, wrapper);
879
903
  }
880
904
 
881
905
  static Napi::Value CallAlloc(const Napi::CallbackInfo &info)
882
906
  {
883
907
  Napi::Env env = info.Env();
884
- InstanceData *instance = env.GetInstanceData<InstanceData>();
908
+ InstanceData *instance = (InstanceData *)info.Data();
885
909
 
886
910
  if (info.Length() < 2) {
887
911
  ThrowError<Napi::TypeError>(env, "Expected 2 arguments, got %1", info.Length());
@@ -892,7 +916,7 @@ static Napi::Value CallAlloc(const Napi::CallbackInfo &info)
892
916
  return env.Null();
893
917
  }
894
918
 
895
- const TypeInfo *type = ResolveType(info[0]);
919
+ const TypeInfo *type = ResolveType(instance, info[0]);
896
920
  if (!type)
897
921
  return env.Null();
898
922
 
@@ -921,12 +945,14 @@ static Napi::Value CallAlloc(const Napi::CallbackInfo &info)
921
945
  return env.Null();
922
946
  }
923
947
 
924
- return WrapPointer(env, type, ptr);
948
+ napi_value wrapper = WrapPointer(env, type, ptr);
949
+ return Napi::Value(env, wrapper);
925
950
  }
926
951
 
927
952
  static Napi::Value CallFree(const Napi::CallbackInfo &info)
928
953
  {
929
954
  Napi::Env env = info.Env();
955
+ InstanceData *instance = (InstanceData *)info.Data();
930
956
 
931
957
  if (info.Length() < 1) {
932
958
  ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
@@ -935,8 +961,6 @@ static Napi::Value CallFree(const Napi::CallbackInfo &info)
935
961
 
936
962
  void *ptr = nullptr;
937
963
  if (!TryPointer(env, info[0], &ptr)) {
938
- InstanceData *instance = Napi::Env(env).GetInstanceData<InstanceData>();
939
-
940
964
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for ptr, expected pointer", GetValueType(instance, info[0]));
941
965
  return env.Null();
942
966
  }
@@ -949,7 +973,7 @@ static Napi::Value CallFree(const Napi::CallbackInfo &info)
949
973
  static Napi::Value GetOrSetErrNo(const Napi::CallbackInfo &info)
950
974
  {
951
975
  Napi::Env env = info.Env();
952
- InstanceData *instance = env.GetInstanceData<InstanceData>();
976
+ InstanceData *instance = (InstanceData *)info.Data();
953
977
 
954
978
  if (info.Length() >= 1) {
955
979
  Napi::Number value = info[0].As<Napi::Number>();
@@ -969,14 +993,14 @@ static Napi::Value GetOrSetErrNo(const Napi::CallbackInfo &info)
969
993
  static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
970
994
  {
971
995
  Napi::Env env = info.Env();
972
- InstanceData *instance = env.GetInstanceData<InstanceData>();
996
+ InstanceData *instance = (InstanceData *)info.Data();
973
997
 
974
998
  if (info.Length() < 2) {
975
999
  ThrowError<Napi::TypeError>(env, "Expected 2 to 4 arguments, got %1", info.Length());
976
1000
  return env.Null();
977
1001
  }
978
1002
 
979
- const TypeInfo *ref = ResolveType(info[0]);
1003
+ const TypeInfo *ref = ResolveType(instance, info[0]);
980
1004
  if (!ref)
981
1005
  return env.Null();
982
1006
 
@@ -1024,10 +1048,19 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
1024
1048
  }
1025
1049
 
1026
1050
  hint = ArrayHint::Typed;
1051
+ } else if (str == "Buffer" || str == "buffer") {
1052
+ if (!(ref->flags & (int)TypeFlag::HasTypedArray)) {
1053
+ ThrowError<Napi::Error>(env, "Array hint 'Buffer' cannot be used with type %1", ref->name);
1054
+ return env.Null();
1055
+ }
1056
+
1057
+ hint = ArrayHint::Buffer;
1027
1058
  } else if (str == "Array" || str == "array") {
1028
1059
  hint = ArrayHint::Array;
1029
1060
  } else if (str == "String" || str == "string") {
1030
- if (ref->primitive != PrimitiveKind::Int8 && ref->primitive != PrimitiveKind::Int16) {
1061
+ if (ref->primitive != PrimitiveKind::Int8 &&
1062
+ ref->primitive != PrimitiveKind::Int16 &&
1063
+ ref->primitive != PrimitiveKind::Int32) {
1031
1064
  ThrowError<Napi::Error>(env, "Array hint 'String' can only be used with 8, 16 and 32-bit signed integer types");
1032
1065
  return env.Null();
1033
1066
  }
@@ -1048,7 +1081,8 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
1048
1081
  type->countedby = DuplicateString(str.Utf8Value().c_str(), &instance->str_alloc).ptr;
1049
1082
  }
1050
1083
 
1051
- return WrapType(env, type);
1084
+ napi_value wrapper = WrapType(instance, type);
1085
+ return Napi::Value(env, wrapper);
1052
1086
  }
1053
1087
 
1054
1088
  static bool ParseClassicFunction(const Napi::CallbackInfo &info, bool concrete, FunctionInfo *out_func)
@@ -1056,7 +1090,7 @@ static bool ParseClassicFunction(const Napi::CallbackInfo &info, bool concrete,
1056
1090
  K_ASSERT(info.Length() >= 2);
1057
1091
 
1058
1092
  Napi::Env env = info.Env();
1059
- InstanceData *instance = env.GetInstanceData<InstanceData>();
1093
+ InstanceData *instance = (InstanceData *)info.Data();
1060
1094
 
1061
1095
  Napi::String name = info[0u].As<Napi::String>();
1062
1096
  Napi::Value ret = info[1u];
@@ -1099,7 +1133,7 @@ static bool ParseClassicFunction(const Napi::CallbackInfo &info, bool concrete,
1099
1133
  // Leave anonymous naming responsibility to caller
1100
1134
  out_func->name = named ? DuplicateString(name.Utf8Value().c_str(), &instance->str_alloc).ptr : nullptr;
1101
1135
 
1102
- out_func->ret.type = ResolveType(ret);
1136
+ out_func->ret.type = ResolveType(instance, ret);
1103
1137
  if (!out_func->ret.type)
1104
1138
  return false;
1105
1139
  if (!CanReturnType(out_func->ret.type)) {
@@ -1126,7 +1160,7 @@ static bool ParseClassicFunction(const Napi::CallbackInfo &info, bool concrete,
1126
1160
  for (uint32_t j = 0; j < parameters_len; j++) {
1127
1161
  ParameterInfo param = {};
1128
1162
 
1129
- param.type = ResolveType(parameters[j], &param.directions);
1163
+ param.type = ResolveType(instance, parameters[j].AsValue(), &param.directions);
1130
1164
 
1131
1165
  if (!param.type)
1132
1166
  return false;
@@ -1152,7 +1186,7 @@ static bool ParseClassicFunction(const Napi::CallbackInfo &info, bool concrete,
1152
1186
  static Napi::Value CreateFunctionType(const Napi::CallbackInfo &info)
1153
1187
  {
1154
1188
  Napi::Env env = info.Env();
1155
- InstanceData *instance = env.GetInstanceData<InstanceData>();
1189
+ InstanceData *instance = (InstanceData *)info.Data();
1156
1190
 
1157
1191
  FunctionInfo *func = instance->callbacks.AppendDefault();
1158
1192
  K_DEFER_N(err_guard) { instance->callbacks.RemoveLast(1); };
@@ -1170,7 +1204,7 @@ static Napi::Value CreateFunctionType(const Napi::CallbackInfo &info)
1170
1204
  }
1171
1205
 
1172
1206
  std::string proto = info[0u].As<Napi::String>();
1173
- if (!ParsePrototype(env, proto.c_str(), false, func))
1207
+ if (!ParsePrototype(instance, proto.c_str(), false, func))
1174
1208
  return env.Null();
1175
1209
  } else {
1176
1210
  ThrowError<Napi::TypeError>(env, "Expected 1 to 4 arguments, got %1", info.Length());
@@ -1195,6 +1229,7 @@ static Napi::Value CreateFunctionType(const Napi::CallbackInfo &info)
1195
1229
 
1196
1230
  TypeInfo *type = instance->types.AppendDefault();
1197
1231
 
1232
+ type->instance = instance;
1198
1233
  type->name = func->name;
1199
1234
 
1200
1235
  type->primitive = PrimitiveKind::Prototype;
@@ -1204,13 +1239,14 @@ static Napi::Value CreateFunctionType(const Napi::CallbackInfo &info)
1204
1239
 
1205
1240
  instance->types_map.Set(type->name, type);
1206
1241
 
1207
- return WrapType(env, type);
1242
+ napi_value wrapper = WrapType(instance, type);
1243
+ return Napi::Value(env, wrapper);
1208
1244
  }
1209
1245
 
1210
1246
  static Napi::Value CreateEnumType(const Napi::CallbackInfo &info)
1211
1247
  {
1212
1248
  Napi::Env env = info.Env();
1213
- InstanceData *instance = env.GetInstanceData<InstanceData>();
1249
+ InstanceData *instance = (InstanceData *)info.Data();
1214
1250
 
1215
1251
  if (info.Length() < 1) {
1216
1252
  ThrowError<Napi::TypeError>(env, "Expected 1 or 2 arguments, got %1", info.Length());
@@ -1236,6 +1272,7 @@ static Napi::Value CreateEnumType(const Napi::CallbackInfo &info)
1236
1272
  TypeInfo *type = instance->types.AppendDefault();
1237
1273
  K_DEFER_N(err_guard) { instance->types.RemoveLast(1); };
1238
1274
 
1275
+ type->instance = instance;
1239
1276
  type->name = named ? DuplicateString(name.Utf8Value().c_str(), &instance->str_alloc).ptr
1240
1277
  : Fmt(&instance->str_alloc, "<anonymous_%1>", instance->types.count).ptr;
1241
1278
 
@@ -1243,7 +1280,7 @@ static Napi::Value CreateEnumType(const Napi::CallbackInfo &info)
1243
1280
 
1244
1281
  // Determine needed storage type
1245
1282
  if (typed) {
1246
- const TypeInfo *storage = ResolveType(info[1 + named]);
1283
+ const TypeInfo *storage = ResolveType(instance, info[1 + named]);
1247
1284
  if (!storage)
1248
1285
  return env.Null();
1249
1286
 
@@ -1360,19 +1397,30 @@ static Napi::Value CreateEnumType(const Napi::CallbackInfo &info)
1360
1397
  return env.Null();
1361
1398
  err_guard.Disable();
1362
1399
 
1363
- Napi::Value wrapper = WrapType(env, type, false);
1364
- Napi::Object defn = type->defn.Value();
1400
+ napi_value wrapper = WrapType(instance, type, false);
1401
+
1402
+ #if defined(EXTERNAL_TYPES)
1403
+ Napi::Object defn;
1404
+ {
1405
+ napi_value value;
1406
+ NAPI_OK(napi_get_reference_value(env, type->defn, &defn));
1407
+
1408
+ defn = Napi::Object(env, value);
1409
+ }
1410
+ #else
1411
+ Napi::Object defn(env, wrapper);
1412
+ #endif
1365
1413
 
1366
1414
  defn.Set("values", values);
1367
1415
  defn.Freeze();
1368
1416
 
1369
- return wrapper;
1417
+ return Napi::Value(env, wrapper);
1370
1418
  }
1371
1419
 
1372
1420
  static Napi::Value CreateTypeAlias(const Napi::CallbackInfo &info)
1373
1421
  {
1374
1422
  Napi::Env env = info.Env();
1375
- InstanceData *instance = env.GetInstanceData<InstanceData>();
1423
+ InstanceData *instance = (InstanceData *)info.Data();
1376
1424
 
1377
1425
  if (info.Length() < 2) {
1378
1426
  ThrowError<Napi::TypeError>(env, "Expected 2 arguments, got %1", info.Length());
@@ -1386,7 +1434,7 @@ static Napi::Value CreateTypeAlias(const Napi::CallbackInfo &info)
1386
1434
  std::string name = info[0].As<Napi::String>();
1387
1435
  const char *alias = DuplicateString(name.c_str(), &instance->str_alloc).ptr;
1388
1436
 
1389
- const TypeInfo *type = ResolveType(info[1]);
1437
+ const TypeInfo *type = ResolveType(instance, info[1]);
1390
1438
  if (!type)
1391
1439
  return env.Null();
1392
1440
 
@@ -1394,23 +1442,26 @@ static Napi::Value CreateTypeAlias(const Napi::CallbackInfo &info)
1394
1442
  if (!MapType(env, instance, type, alias))
1395
1443
  return env.Null();
1396
1444
 
1397
- return WrapType(env, type);
1445
+ napi_value wrapper = WrapType(instance, type);
1446
+ return Napi::Value(env, wrapper);
1398
1447
  }
1399
1448
 
1400
1449
  static Napi::Value GetResolvedType(const Napi::CallbackInfo &info)
1401
1450
  {
1402
1451
  Napi::Env env = info.Env();
1452
+ InstanceData *instance = (InstanceData *)info.Data();
1403
1453
 
1404
1454
  if (info.Length() < 1) {
1405
1455
  ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
1406
1456
  return env.Null();
1407
1457
  }
1408
1458
 
1409
- const TypeInfo *type = ResolveType(info[0]);
1459
+ const TypeInfo *type = ResolveType(instance, info[0]);
1410
1460
  if (!type)
1411
1461
  return env.Null();
1412
1462
 
1413
- return WrapType(env, type);
1463
+ napi_value wrapper = WrapType(instance, type);
1464
+ return Napi::Value(env, wrapper);
1414
1465
  }
1415
1466
 
1416
1467
  #if defined(EXTERNAL_TYPES)
@@ -1418,20 +1469,24 @@ static Napi::Value GetResolvedType(const Napi::CallbackInfo &info)
1418
1469
  static Napi::Value GetTypeDefinition(const Napi::CallbackInfo &info)
1419
1470
  {
1420
1471
  Napi::Env env = info.Env();
1472
+ InstanceData *instance = (InstanceData *)info.Data();
1421
1473
 
1422
1474
  if (info.Length() < 1) {
1423
1475
  ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
1424
1476
  return env.Null();
1425
1477
  }
1426
1478
 
1427
- const TypeInfo *type = ResolveType(info[0]);
1479
+ const TypeInfo *type = ResolveType(instance, info[0]);
1428
1480
  if (!type)
1429
1481
  return env.Null();
1430
1482
 
1431
1483
  // Make sure definition is available
1432
- WrapType(env, type);
1484
+ WrapType(instance, type);
1433
1485
 
1434
- return type->defn.Value();
1486
+ napi_value defn;
1487
+ NAPI_OK(napi_get_reference_value(env, instance->defn, &defn));
1488
+
1489
+ return defn;
1435
1490
  }
1436
1491
 
1437
1492
  #endif
@@ -1530,13 +1585,32 @@ void ReleaseMemory(InstanceData *instance, InstanceMemory *mem)
1530
1585
  }
1531
1586
  }
1532
1587
 
1533
- Napi::Function LibraryHandle::InitClass(Napi::Env env)
1588
+ TypeInfo::~TypeInfo()
1589
+ {
1590
+ if (!instance)
1591
+ return;
1592
+
1593
+ Napi::Env env = instance->env;
1594
+
1595
+ for (RecordMember &member: members) {
1596
+ node_api_delete_reference(env, member.key);
1597
+ member.key = nullptr;
1598
+ }
1599
+
1600
+ node_api_delete_reference(env, dispose_ref);
1601
+ node_api_delete_reference(env, construct);
1602
+ node_api_delete_reference(env, defn);
1603
+ }
1604
+
1605
+ Napi::Function LibraryHandle::InitClass(InstanceData *instance)
1534
1606
  {
1607
+ Napi::Env env = instance->env;
1608
+
1535
1609
  // node-addon-api wants std::vector
1536
1610
  std::vector<Napi::ClassPropertyDescriptor<LibraryHandle>> properties = {
1537
- InstanceMethod("func", &LibraryHandle::Func),
1538
- InstanceMethod("symbol", &LibraryHandle::Symbol),
1539
- InstanceMethod("unload", &LibraryHandle::Unload)
1611
+ InstanceMethod("func", &LibraryHandle::Func, napi_default, instance),
1612
+ InstanceMethod("symbol", &LibraryHandle::Symbol, napi_default, instance),
1613
+ InstanceMethod("unload", &LibraryHandle::Unload, napi_default, instance)
1540
1614
  };
1541
1615
 
1542
1616
  if (Napi::Value dispose = env.RunScript("Symbol.dispose"); !IsNullOrUndefined(env, dispose)) {
@@ -1564,7 +1638,7 @@ LibraryHandle::LibraryHandle(const Napi::CallbackInfo &info)
1564
1638
 
1565
1639
  void LibraryHandle::Finalize(Napi::BasicEnv env)
1566
1640
  {
1567
- DeleteReferenceSafe(env, *this);
1641
+ node_api_delete_reference(env, *this);
1568
1642
  SuppressDestruct();
1569
1643
 
1570
1644
  lib->Unref();
@@ -1573,7 +1647,7 @@ void LibraryHandle::Finalize(Napi::BasicEnv env)
1573
1647
  Napi::Value LibraryHandle::Func(const Napi::CallbackInfo &info)
1574
1648
  {
1575
1649
  Napi::Env env = info.Env();
1576
- InstanceData *instance = env.GetInstanceData<InstanceData>();
1650
+ InstanceData *instance = (InstanceData *)info.Data();
1577
1651
 
1578
1652
  FunctionInfo *func = new FunctionInfo();
1579
1653
  K_DEFER { func->Unref(); };
@@ -1592,7 +1666,7 @@ Napi::Value LibraryHandle::Func(const Napi::CallbackInfo &info)
1592
1666
  }
1593
1667
 
1594
1668
  std::string proto = info[0u].As<Napi::String>();
1595
- if (!ParsePrototype(env, proto.c_str(), true, func))
1669
+ if (!ParsePrototype(instance, proto.c_str(), true, func))
1596
1670
  return env.Null();
1597
1671
  } else {
1598
1672
  ThrowError<Napi::TypeError>(env, "Expected 1 to 4 arguments, got %1", info.Length());
@@ -1635,28 +1709,40 @@ Napi::Value LibraryHandle::Func(const Napi::CallbackInfo &info)
1635
1709
  return env.Null();
1636
1710
  }
1637
1711
 
1638
- return WrapFunction(env, func);
1712
+ napi_value wrapper = WrapFunction(instance, func);
1713
+ return Napi::Value(env, wrapper);
1639
1714
  }
1640
1715
 
1641
1716
  Napi::Value LibraryHandle::Symbol(const Napi::CallbackInfo &info)
1642
1717
  {
1643
1718
  Napi::Env env = info.Env();
1644
- InstanceData *instance = env.GetInstanceData<InstanceData>();
1719
+ InstanceData *instance = (InstanceData *)info.Data();
1645
1720
 
1721
+ #if defined(EXTERNAL_POINTERS)
1646
1722
  if (info.Length() < 2) {
1647
- ThrowError<Napi::TypeError>(env, "Expected 2, got %1", info.Length());
1723
+ ThrowError<Napi::TypeError>(env, "Expected 2 arguments, got %1", info.Length());
1648
1724
  return env.Null();
1649
1725
  }
1650
- if (!info[0].IsString()) {
1726
+ #else
1727
+ if (info.Length() < 1) {
1728
+ ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
1729
+ return env.Null();
1730
+ }
1731
+ #endif
1732
+ if (!info[0].IsString()) {
1651
1733
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
1652
1734
  return env.Null();
1653
1735
  }
1654
1736
 
1655
1737
  std::string name = info[0].As<Napi::String>();
1656
1738
 
1657
- const TypeInfo *type = ResolveType(info[1]);
1739
+ #if defined(EXTERNAL_POINTERS)
1740
+ const TypeInfo *type = ResolveType(instance, info[1]);
1658
1741
  if (!type)
1659
1742
  return env.Null();
1743
+ #else
1744
+ const TypeInfo *type = nullptr;
1745
+ #endif
1660
1746
 
1661
1747
  #if defined(_WIN32)
1662
1748
  void *ptr = (void *)GetProcAddress((HMODULE)lib->module, name.c_str());
@@ -1668,7 +1754,8 @@ Napi::Value LibraryHandle::Symbol(const Napi::CallbackInfo &info)
1668
1754
  return env.Null();
1669
1755
  }
1670
1756
 
1671
- return WrapPointer(env, type, ptr);
1757
+ napi_value wrapper = WrapPointer(env, type, ptr);
1758
+ return Napi::Value(env, wrapper);
1672
1759
  }
1673
1760
 
1674
1761
  Napi::Value LibraryHandle::Unload(const Napi::CallbackInfo &info)
@@ -1683,7 +1770,7 @@ Napi::Value LibraryHandle::Unload(const Napi::CallbackInfo &info)
1683
1770
  static Napi::Value LoadSharedLibrary(const Napi::CallbackInfo &info)
1684
1771
  {
1685
1772
  Napi::Env env = info.Env();
1686
- InstanceData *instance = env.GetInstanceData<InstanceData>();
1773
+ InstanceData *instance = (InstanceData *)info.Data();
1687
1774
 
1688
1775
  if (info.Length() < 1) {
1689
1776
  ThrowError<Napi::TypeError>(env, "Expected 1 or 2 arguments, got %1", info.Length());
@@ -1768,7 +1855,7 @@ static Napi::Value LoadSharedLibrary(const Napi::CallbackInfo &info)
1768
1855
  static Napi::Value RegisterCallback(const Napi::CallbackInfo &info)
1769
1856
  {
1770
1857
  Napi::Env env = info.Env();
1771
- InstanceData *instance = env.GetInstanceData<InstanceData>();
1858
+ InstanceData *instance = (InstanceData *)info.Data();
1772
1859
 
1773
1860
  if (!InitAsyncBroker(env, instance)) [[unlikely]]
1774
1861
  return env.Null();
@@ -1784,7 +1871,7 @@ static Napi::Value RegisterCallback(const Napi::CallbackInfo &info)
1784
1871
 
1785
1872
  Napi::Function func = info[0].As<Napi::Function>();
1786
1873
 
1787
- const TypeInfo *type = ResolveType(info[1]);
1874
+ const TypeInfo *type = ResolveType(instance, info[1]);
1788
1875
  if (!type)
1789
1876
  return env.Null();
1790
1877
  if (type->primitive != PrimitiveKind::Callback) {
@@ -1811,20 +1898,21 @@ static Napi::Value RegisterCallback(const Napi::CallbackInfo &info)
1811
1898
  trampoline->instance = instance;
1812
1899
  trampoline->stack0 = instance->memories[0]->stack0;
1813
1900
  trampoline->proto = type->proto;
1814
- napi_create_reference(env, func, 1, &trampoline->func);
1901
+ NAPI_OK(napi_create_reference(env, func, 1, &trampoline->func));
1815
1902
 
1816
1903
  void *ptr = GetTrampoline(idx);
1817
1904
 
1818
1905
  // Cache index for fast unregistration
1819
1906
  instance->trampolines_map.Set(ptr, idx);
1820
1907
 
1821
- return WrapPointer(env, type->ref.type, ptr);
1908
+ napi_value wrapper = WrapPointer(env, type->ref.type, ptr);
1909
+ return Napi::Value(env, wrapper);
1822
1910
  }
1823
1911
 
1824
1912
  static Napi::Value UnregisterCallback(const Napi::CallbackInfo &info)
1825
1913
  {
1826
1914
  Napi::Env env = info.Env();
1827
- InstanceData *instance = env.GetInstanceData<InstanceData>();
1915
+ InstanceData *instance = (InstanceData *)info.Data();
1828
1916
 
1829
1917
  if (info.Length() < 1) {
1830
1918
  ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
@@ -1858,7 +1946,7 @@ static Napi::Value UnregisterCallback(const Napi::CallbackInfo &info)
1858
1946
  K_ASSERT(trampoline->func);
1859
1947
 
1860
1948
  trampoline->state = 0;
1861
- napi_delete_reference(env, trampoline->func);
1949
+ node_api_delete_reference(env, trampoline->func);
1862
1950
  trampoline->func = nullptr;
1863
1951
 
1864
1952
  shared.available.Append(idx);
@@ -1870,6 +1958,7 @@ static Napi::Value UnregisterCallback(const Napi::CallbackInfo &info)
1870
1958
  static Napi::Value CastValue(const Napi::CallbackInfo &info)
1871
1959
  {
1872
1960
  Napi::Env env = info.Env();
1961
+ InstanceData *instance = (InstanceData *)info.Data();
1873
1962
 
1874
1963
  if (info.Length() < 2) [[unlikely]] {
1875
1964
  ThrowError<Napi::TypeError>(env, "Expected 2 arguments, got %1", info.Length());
@@ -1878,7 +1967,7 @@ static Napi::Value CastValue(const Napi::CallbackInfo &info)
1878
1967
 
1879
1968
  Napi::Value value = info[0];
1880
1969
 
1881
- const TypeInfo *type = ResolveType(info[1]);
1970
+ const TypeInfo *type = ResolveType(instance, info[1]);
1882
1971
  if (!type) [[unlikely]]
1883
1972
  return env.Null();
1884
1973
  if (type->primitive != PrimitiveKind::Pointer &&
@@ -1893,10 +1982,10 @@ static Napi::Value CastValue(const Napi::CallbackInfo &info)
1893
1982
  ValueCast *cast = new ValueCast();
1894
1983
 
1895
1984
  cast->env = env;
1896
- napi_create_reference(env, value, 1, &cast->ref);
1985
+ NAPI_OK(napi_create_reference(env, value, 1, &cast->ref));
1897
1986
  cast->type = type;
1898
1987
 
1899
- Napi::External<ValueCast> external = Napi::External<ValueCast>::New(env, cast, [](Napi::Env, ValueCast *cast) { delete cast; });
1988
+ Napi::External<ValueCast> external = Napi::External<ValueCast>::New(env, cast, [](Napi::BasicEnv, ValueCast *cast) { delete cast; });
1900
1989
  SetValueTag(env, external, &CastMarker);
1901
1990
 
1902
1991
  return external;
@@ -1905,6 +1994,7 @@ static Napi::Value CastValue(const Napi::CallbackInfo &info)
1905
1994
  static Napi::Value DecodeValue(const Napi::CallbackInfo &info)
1906
1995
  {
1907
1996
  Napi::Env env = info.Env();
1997
+ InstanceData *instance = (InstanceData *)info.Data();
1908
1998
 
1909
1999
  bool has_offset = (info.Length() >= 2 && info[1].IsNumber());
1910
2000
  bool has_len = (info.Length() >= 3u + has_offset && info[2 + has_offset].IsNumber());
@@ -1914,22 +2004,78 @@ static Napi::Value DecodeValue(const Napi::CallbackInfo &info)
1914
2004
  return env.Null();
1915
2005
  }
1916
2006
 
1917
- const TypeInfo *type = ResolveType(info[1u + has_offset]);
2007
+ const TypeInfo *type = ResolveType(instance, info[1u + has_offset]);
1918
2008
  if (!type) [[unlikely]]
1919
2009
  return env.Null();
1920
2010
 
1921
- Napi::Value value = info[0];
2011
+ napi_value ref = info[0];
1922
2012
  int64_t offset = has_offset ? info[1].As<Napi::Number>().Int64Value() : 0;
1923
2013
 
2014
+ const void *src = nullptr;
2015
+ Size len = 0;
2016
+
2017
+ if (!TryPointer(env, ref, (void **)&src, &len)) {
2018
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for reference, expected pointer", GetValueType(instance, ref));
2019
+ return env.Null();
2020
+ }
2021
+
2022
+ if (len >= 0) {
2023
+ if (offset < 0) [[unlikely]] {
2024
+ ThrowError<Napi::Error>(env, "Offset must be >= 0");
2025
+ return env.Null();
2026
+ }
2027
+ if (len - offset < type->size) [[unlikely]] {
2028
+ ThrowError<Napi::Error>(env, "Expected buffer with size superior or equal to type %1 (%2 bytes)",
2029
+ type->name, type->size + offset);
2030
+ return env.Null();
2031
+ }
2032
+ }
2033
+
2034
+ if (!src) [[unlikely]] {
2035
+ ThrowError<Napi::Error>(env, "Cannot encode data in NULL pointer");
2036
+ return env.Null();
2037
+ }
2038
+
2039
+ src = (const void *)((const uint8_t *)src + offset);
2040
+
1924
2041
  if (has_len) {
1925
2042
  Size len = info[2 + has_offset].As<Napi::Number>();
1926
2043
 
1927
- napi_value ret = Decode(value, (Size)offset, type, &len);
1928
- return Napi::Value(env, ret);
1929
- } else {
1930
- napi_value ret = Decode(value, (Size)offset, type);
1931
- return Napi::Value(env, ret);
2044
+ if (len >= 0) {
2045
+ type = MakeArrayType(instance, type, len);
2046
+ } else {
2047
+ switch (type->primitive) {
2048
+ case PrimitiveKind::Int8:
2049
+ case PrimitiveKind::UInt8: {
2050
+ Size count = strlen((const char *)src);
2051
+ type = MakeArrayType(instance, type, count);
2052
+ } break;
2053
+ case PrimitiveKind::Int16:
2054
+ case PrimitiveKind::UInt16: {
2055
+ Size count = NullTerminatedLength((const char16_t *)src);
2056
+ type = MakeArrayType(instance, type, count);
2057
+ } break;
2058
+ case PrimitiveKind::Int32:
2059
+ case PrimitiveKind::UInt32: {
2060
+ Size count = NullTerminatedLength((const char32_t *)src);
2061
+ type = MakeArrayType(instance, type, count);
2062
+ } break;
2063
+
2064
+ case PrimitiveKind::Pointer: {
2065
+ Size count = NullTerminatedLength((const void **)src);
2066
+ type = MakeArrayType(instance, type, count);
2067
+ } break;
2068
+
2069
+ default: {
2070
+ ThrowError<Napi::TypeError>(env, "Cannot determine null-terminated length for type %1", type->name);
2071
+ return env.Null();
2072
+ } break;
2073
+ }
2074
+ }
1932
2075
  }
2076
+
2077
+ napi_value ret = Decode(instance, (const uint8_t *)src, type);
2078
+ return Napi::Value(env, ret);
1933
2079
  }
1934
2080
 
1935
2081
  template <typename T>
@@ -1937,9 +2083,9 @@ static FORCE_INLINE napi_value DecodeInteger(napi_env env, napi_callback_info in
1937
2083
  {
1938
2084
  napi_value arg;
1939
2085
  size_t count = 1;
2086
+ InstanceData *instance;
1940
2087
 
1941
- napi_status status = napi_get_cb_info(env, info, &count, &arg, nullptr, nullptr);
1942
- K_ASSERT(status == napi_ok);
2088
+ NAPI_OK(napi_get_cb_info(env, info, &count, &arg, nullptr, (void **)&instance));
1943
2089
 
1944
2090
  if (count < 1) [[unlikely]] {
1945
2091
  ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", count);
@@ -1948,8 +2094,6 @@ static FORCE_INLINE napi_value DecodeInteger(napi_env env, napi_callback_info in
1948
2094
 
1949
2095
  void *ptr = nullptr;
1950
2096
  if (!TryPointer(env, arg, &ptr)) [[unlikely]] {
1951
- InstanceData *instance = Napi::Env(env).GetInstanceData<InstanceData>();
1952
-
1953
2097
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for ptr, expected pointer", GetValueType(instance, arg));
1954
2098
  return Napi::Env(env).Null();
1955
2099
  }
@@ -1960,13 +2104,14 @@ static FORCE_INLINE napi_value DecodeInteger(napi_env env, napi_callback_info in
1960
2104
  return NewInt(env, i);
1961
2105
  }
1962
2106
 
1963
- static napi_value DecodeFloat(napi_env env, napi_callback_info info)
2107
+ template <typename T>
2108
+ static FORCE_INLINE napi_value DecodeIntegerSwap(napi_env env, napi_callback_info info)
1964
2109
  {
1965
2110
  napi_value arg;
1966
2111
  size_t count = 1;
2112
+ InstanceData *instance;
1967
2113
 
1968
- napi_status status = napi_get_cb_info(env, info, &count, &arg, nullptr, nullptr);
1969
- K_ASSERT(status == napi_ok);
2114
+ NAPI_OK(napi_get_cb_info(env, info, &count, &arg, nullptr, (void **)&instance));
1970
2115
 
1971
2116
  if (count < 1) [[unlikely]] {
1972
2117
  ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", count);
@@ -1975,8 +2120,47 @@ static napi_value DecodeFloat(napi_env env, napi_callback_info info)
1975
2120
 
1976
2121
  void *ptr = nullptr;
1977
2122
  if (!TryPointer(env, arg, &ptr)) [[unlikely]] {
1978
- InstanceData *instance = Napi::Env(env).GetInstanceData<InstanceData>();
2123
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for ptr, expected pointer", GetValueType(instance, arg));
2124
+ return Napi::Env(env).Null();
2125
+ }
2126
+
2127
+ T i;
2128
+ memcpy(&i, ptr, K_SIZE(i));
2129
+
2130
+ return NewInt(env, ReverseBytes(i));
2131
+ }
2132
+
2133
+ #if defined(K_BIG_ENDIAN)
2134
+
2135
+ template <typename T>
2136
+ static FORCE_INLINE napi_value DecodeIntegerLE(napi_env env, napi_callback_info info) { return DecodeIntegerSwap<T>(env, info); }
2137
+ template <typename T>
2138
+ static FORCE_INLINE napi_value DecodeIntegerBE(napi_env env, napi_callback_info info) { return DecodeInteger<T>(env, info); }
2139
+
2140
+ #else
1979
2141
 
2142
+ template <typename T>
2143
+ static FORCE_INLINE napi_value DecodeIntegerLE(napi_env env, napi_callback_info info) { return DecodeInteger<T>(env, info); }
2144
+ template <typename T>
2145
+ static FORCE_INLINE napi_value DecodeIntegerBE(napi_env env, napi_callback_info info) { return DecodeIntegerSwap<T>(env, info); }
2146
+
2147
+ #endif
2148
+
2149
+ static napi_value DecodeFloat(napi_env env, napi_callback_info info)
2150
+ {
2151
+ napi_value arg;
2152
+ size_t count = 1;
2153
+ InstanceData *instance;
2154
+
2155
+ NAPI_OK(napi_get_cb_info(env, info, &count, &arg, nullptr, (void **)&instance));
2156
+
2157
+ if (count < 1) [[unlikely]] {
2158
+ ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", count);
2159
+ return Napi::Env(env).Null();
2160
+ }
2161
+
2162
+ void *ptr = nullptr;
2163
+ if (!TryPointer(env, arg, &ptr)) [[unlikely]] {
1980
2164
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for ptr, expected pointer", GetValueType(instance, arg));
1981
2165
  return Napi::Env(env).Null();
1982
2166
  }
@@ -1984,16 +2168,16 @@ static napi_value DecodeFloat(napi_env env, napi_callback_info info)
1984
2168
  float f;
1985
2169
  memcpy(&f, ptr, K_SIZE(f));
1986
2170
 
1987
- return Napi::Number::New(env, (double)f);
2171
+ return NewFloat(env, f);
1988
2172
  }
1989
2173
 
1990
2174
  static napi_value DecodeDouble(napi_env env, napi_callback_info info)
1991
2175
  {
1992
2176
  napi_value arg;
1993
2177
  size_t count = 1;
2178
+ InstanceData *instance;
1994
2179
 
1995
- napi_status status = napi_get_cb_info(env, info, &count, &arg, nullptr, nullptr);
1996
- K_ASSERT(status == napi_ok);
2180
+ NAPI_OK(napi_get_cb_info(env, info, &count, &arg, nullptr, (void **)&instance));
1997
2181
 
1998
2182
  if (count < 1) [[unlikely]] {
1999
2183
  ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", count);
@@ -2002,8 +2186,6 @@ static napi_value DecodeDouble(napi_env env, napi_callback_info info)
2002
2186
 
2003
2187
  void *ptr = nullptr;
2004
2188
  if (!TryPointer(env, arg, &ptr)) [[unlikely]] {
2005
- InstanceData *instance = Napi::Env(env).GetInstanceData<InstanceData>();
2006
-
2007
2189
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for ptr, expected pointer", GetValueType(instance, arg));
2008
2190
  return Napi::Env(env).Null();
2009
2191
  }
@@ -2011,16 +2193,16 @@ static napi_value DecodeDouble(napi_env env, napi_callback_info info)
2011
2193
  double d;
2012
2194
  memcpy(&d, ptr, K_SIZE(d));
2013
2195
 
2014
- return Napi::Number::New(env, d);
2196
+ return NewFloat(env, d);
2015
2197
  }
2016
2198
 
2017
2199
  static napi_value DecodeString(napi_env env, napi_callback_info info)
2018
2200
  {
2019
2201
  napi_value args[2];
2020
2202
  size_t count = 2;
2203
+ InstanceData *instance;
2021
2204
 
2022
- napi_status status = napi_get_cb_info(env, info, &count, args, nullptr, nullptr);
2023
- K_ASSERT(status == napi_ok);
2205
+ NAPI_OK(napi_get_cb_info(env, info, &count, args, nullptr, (void **)&instance));
2024
2206
 
2025
2207
  if (count < 1) [[unlikely]] {
2026
2208
  ThrowError<Napi::TypeError>(env, "Expected 1 to 2 arguments, got %1", count);
@@ -2029,8 +2211,6 @@ static napi_value DecodeString(napi_env env, napi_callback_info info)
2029
2211
 
2030
2212
  void *ptr = nullptr;
2031
2213
  if (!TryPointer(env, args[0], &ptr)) [[unlikely]] {
2032
- InstanceData *instance = Napi::Env(env).GetInstanceData<InstanceData>();
2033
-
2034
2214
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for ptr, expected pointer", GetValueType(instance, args[0]));
2035
2215
  return Napi::Env(env).Null();
2036
2216
  }
@@ -2038,15 +2218,13 @@ static napi_value DecodeString(napi_env env, napi_callback_info info)
2038
2218
  if (count >= 2) {
2039
2219
  Size len;
2040
2220
  if (!TryNumber(env, args[1], &len)) [[unlikely]] {
2041
- InstanceData *instance = Napi::Env(env).GetInstanceData<InstanceData>();
2042
-
2043
2221
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for length, expected number", GetValueType(instance, args[1]));
2044
2222
  return Napi::Env(env).Null();
2045
2223
  }
2046
2224
 
2047
- return Napi::String::New(env, (const char *)ptr, (size_t)len);
2225
+ return NewString(env, (const char *)ptr, (size_t)len);
2048
2226
  } else {
2049
- return Napi::String::New(env, (const char *)ptr);
2227
+ return NewString(env, (const char *)ptr);
2050
2228
  }
2051
2229
  }
2052
2230
 
@@ -2054,9 +2232,9 @@ static napi_value DecodeString16(napi_env env, napi_callback_info info)
2054
2232
  {
2055
2233
  napi_value args[2];
2056
2234
  size_t count = 2;
2235
+ InstanceData *instance;
2057
2236
 
2058
- napi_status status = napi_get_cb_info(env, info, &count, args, nullptr, nullptr);
2059
- K_ASSERT(status == napi_ok);
2237
+ NAPI_OK(napi_get_cb_info(env, info, &count, args, nullptr, (void **)&instance));
2060
2238
 
2061
2239
  if (count < 1) [[unlikely]] {
2062
2240
  ThrowError<Napi::TypeError>(env, "Expected 1 to 2 arguments, got %1", count);
@@ -2065,8 +2243,6 @@ static napi_value DecodeString16(napi_env env, napi_callback_info info)
2065
2243
 
2066
2244
  void *ptr = nullptr;
2067
2245
  if (!TryPointer(env, args[0], &ptr)) [[unlikely]] {
2068
- InstanceData *instance = Napi::Env(env).GetInstanceData<InstanceData>();
2069
-
2070
2246
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for ptr, expected pointer", GetValueType(instance, args[0]));
2071
2247
  return Napi::Env(env).Null();
2072
2248
  }
@@ -2074,15 +2250,13 @@ static napi_value DecodeString16(napi_env env, napi_callback_info info)
2074
2250
  if (count >= 2) {
2075
2251
  Size len;
2076
2252
  if (!TryNumber(env, args[1], &len)) [[unlikely]] {
2077
- InstanceData *instance = Napi::Env(env).GetInstanceData<InstanceData>();
2078
-
2079
2253
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for length, expected number", GetValueType(instance, args[1]));
2080
2254
  return Napi::Env(env).Null();
2081
2255
  }
2082
2256
 
2083
- return Napi::String::New(env, (const char16_t *)ptr, (size_t)len);
2257
+ return NewString(env, (const char16_t *)ptr, (size_t)len);
2084
2258
  } else {
2085
- return Napi::String::New(env, (const char16_t *)ptr);
2259
+ return NewString(env, (const char16_t *)ptr);
2086
2260
  }
2087
2261
  }
2088
2262
 
@@ -2090,9 +2264,9 @@ static napi_value DecodeString32(napi_env env, napi_callback_info info)
2090
2264
  {
2091
2265
  napi_value args[2];
2092
2266
  size_t count = 2;
2267
+ InstanceData *instance;
2093
2268
 
2094
- napi_status status = napi_get_cb_info(env, info, &count, args, nullptr, nullptr);
2095
- K_ASSERT(status == napi_ok);
2269
+ NAPI_OK(napi_get_cb_info(env, info, &count, args, nullptr, (void **)&instance));
2096
2270
 
2097
2271
  if (count < 1) [[unlikely]] {
2098
2272
  ThrowError<Napi::TypeError>(env, "Expected 1 to 2 arguments, got %1", count);
@@ -2101,8 +2275,6 @@ static napi_value DecodeString32(napi_env env, napi_callback_info info)
2101
2275
 
2102
2276
  void *ptr = nullptr;
2103
2277
  if (!TryPointer(env, args[0], &ptr)) [[unlikely]] {
2104
- InstanceData *instance = Napi::Env(env).GetInstanceData<InstanceData>();
2105
-
2106
2278
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for ptr, expected pointer", GetValueType(instance, args[0]));
2107
2279
  return Napi::Env(env).Null();
2108
2280
  }
@@ -2110,21 +2282,20 @@ static napi_value DecodeString32(napi_env env, napi_callback_info info)
2110
2282
  if (count >= 2) {
2111
2283
  Size len;
2112
2284
  if (!TryNumber(env, args[1], &len)) [[unlikely]] {
2113
- InstanceData *instance = Napi::Env(env).GetInstanceData<InstanceData>();
2114
-
2115
2285
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for length, expected number", GetValueType(instance, args[1]));
2116
2286
  return Napi::Env(env).Null();
2117
2287
  }
2118
2288
 
2119
- return MakeStringFromUTF32(env, (const char32_t *)ptr, len);
2289
+ return NewString(env, (const char32_t *)ptr, len);
2120
2290
  } else {
2121
- return MakeStringFromUTF32(env, (const char32_t *)ptr);
2291
+ return NewString(env, (const char32_t *)ptr);
2122
2292
  }
2123
2293
  }
2124
2294
 
2125
2295
  static Napi::Value GetPointerAddress(const Napi::CallbackInfo &info)
2126
2296
  {
2127
2297
  Napi::Env env = info.Env();
2298
+ InstanceData *instance = (InstanceData *)info.Data();
2128
2299
 
2129
2300
  if (info.Length() < 1) {
2130
2301
  ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
@@ -2133,8 +2304,6 @@ static Napi::Value GetPointerAddress(const Napi::CallbackInfo &info)
2133
2304
 
2134
2305
  void *ptr = nullptr;
2135
2306
  if (!TryPointer(env, info[0], &ptr)) {
2136
- InstanceData *instance = Napi::Env(env).GetInstanceData<InstanceData>();
2137
-
2138
2307
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for ptr, expected pointer", GetValueType(instance, info[0]));
2139
2308
  return env.Null();
2140
2309
  }
@@ -2148,6 +2317,7 @@ static Napi::Value GetPointerAddress(const Napi::CallbackInfo &info)
2148
2317
  static Napi::Value CallPointerSync(const Napi::CallbackInfo &info)
2149
2318
  {
2150
2319
  Napi::Env env = info.Env();
2320
+ InstanceData *instance = (InstanceData *)info.Data();
2151
2321
 
2152
2322
  if (info.Length() < 2) [[unlikely]] {
2153
2323
  ThrowError<Napi::TypeError>(env, "Expected 2 or more arguments, got %1", info.Length());
@@ -2156,18 +2326,14 @@ static Napi::Value CallPointerSync(const Napi::CallbackInfo &info)
2156
2326
 
2157
2327
  void *ptr = nullptr;
2158
2328
  if (!TryPointer(env, info[0], &ptr)) {
2159
- InstanceData *instance = Napi::Env(env).GetInstanceData<InstanceData>();
2160
-
2161
2329
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for ptr, expected pointer", GetValueType(instance, info[0]));
2162
2330
  return env.Null();
2163
2331
  }
2164
2332
 
2165
- const TypeInfo *type = ResolveType(info[1]);
2333
+ const TypeInfo *type = ResolveType(instance, info[1]);
2166
2334
  if (!type) [[unlikely]]
2167
2335
  return env.Null();
2168
2336
  if (type->primitive != PrimitiveKind::Prototype) [[unlikely]] {
2169
- InstanceData *instance = env.GetInstanceData<InstanceData>();
2170
-
2171
2337
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for type, expected function type", GetValueType(instance, info[1]));
2172
2338
  return env.Null();
2173
2339
  }
@@ -2179,6 +2345,7 @@ static Napi::Value CallPointerSync(const Napi::CallbackInfo &info)
2179
2345
  static Napi::Value EncodeValue(const Napi::CallbackInfo &info)
2180
2346
  {
2181
2347
  Napi::Env env = info.Env();
2348
+ InstanceData *instance = (InstanceData *)info.Data();
2182
2349
 
2183
2350
  bool has_offset = (info.Length() >= 2 && info[1].IsNumber());
2184
2351
  bool has_len = (info.Length() >= 4u + has_offset && info[3 + has_offset].IsNumber());
@@ -2188,7 +2355,7 @@ static Napi::Value EncodeValue(const Napi::CallbackInfo &info)
2188
2355
  return env.Null();
2189
2356
  }
2190
2357
 
2191
- const TypeInfo *type = ResolveType(info[1u + has_offset]);
2358
+ const TypeInfo *type = ResolveType(instance, info[1u + has_offset]);
2192
2359
  if (!type) [[unlikely]]
2193
2360
  return env.Null();
2194
2361
 
@@ -2196,38 +2363,71 @@ static Napi::Value EncodeValue(const Napi::CallbackInfo &info)
2196
2363
  int64_t offset = has_offset ? info[1].As<Napi::Number>().Int64Value() : 0;
2197
2364
  Napi::Value value = info[2 + has_offset];
2198
2365
 
2199
- if (has_len) {
2200
- Size len = info[3 + has_offset].As<Napi::Number>();
2366
+ void *dest = nullptr;
2367
+ Size len = 0;
2201
2368
 
2202
- if (!Encode(ref, (Size)offset, value, type, &len))
2369
+ if (!TryPointer(env, ref, &dest, &len)) {
2370
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for reference, expected pointer", GetValueType(instance, ref));
2371
+ return env.Null();
2372
+ }
2373
+
2374
+ if (len >= 0) {
2375
+ if (offset < 0) [[unlikely]] {
2376
+ ThrowError<Napi::Error>(env, "Offset must be >= 0");
2203
2377
  return env.Null();
2204
- } else {
2205
- if (!Encode(ref, (Size)offset, value, type))
2378
+ }
2379
+ if (len - offset < type->size) [[unlikely]] {
2380
+ ThrowError<Napi::Error>(env, "Expected buffer with size superior or equal to type %1 (%2 bytes)",
2381
+ type->name, type->size + offset);
2206
2382
  return env.Null();
2383
+ }
2384
+ }
2385
+
2386
+ if (!dest) [[unlikely]] {
2387
+ ThrowError<Napi::Error>(env, "Cannot encode data in NULL pointer");
2388
+ return env.Null();
2389
+ }
2390
+
2391
+ dest = (void *)((uint8_t *)dest + offset);
2392
+
2393
+ if (has_len) {
2394
+ Size len = info[3 + has_offset].As<Napi::Number>();
2395
+
2396
+ if (type->primitive != PrimitiveKind::String &&
2397
+ type->primitive != PrimitiveKind::String16 &&
2398
+ type->primitive != PrimitiveKind::String32 &&
2399
+ type->primitive != PrimitiveKind::Prototype) {
2400
+ if (len < 0) [[unlikely]] {
2401
+ ThrowError<Napi::TypeError>(env, "Automatic (negative) length is only supported when decoding");
2402
+ return env.Null();
2403
+ }
2404
+
2405
+ type = MakeArrayType(instance, type, len);
2406
+ }
2207
2407
  }
2208
2408
 
2409
+ if (!Encode(instance, (uint8_t *)dest, value, type))
2410
+ return env.Null();
2411
+
2209
2412
  return env.Undefined();
2210
2413
  }
2211
2414
 
2212
2415
  static Napi::Value CreateView(const Napi::CallbackInfo &info)
2213
2416
  {
2214
2417
  Napi::Env env = info.Env();
2418
+ InstanceData *instance = (InstanceData *)info.Data();
2215
2419
 
2216
2420
  if (info.Length() < 1) {
2217
2421
  ThrowError<Napi::TypeError>(env, "Expected 2 arguments, got %1", info.Length());
2218
2422
  return env.Null();
2219
2423
  }
2220
2424
  if (!info[1].IsNumber()) {
2221
- InstanceData *instance = env.GetInstanceData<InstanceData>();
2222
-
2223
2425
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for length, expected integer", GetValueType(instance, info[1]));
2224
2426
  return env.Null();
2225
2427
  }
2226
2428
 
2227
2429
  void *ptr = nullptr;
2228
2430
  if (!TryPointer(env, info[0], &ptr)) {
2229
- InstanceData *instance = Napi::Env(env).GetInstanceData<InstanceData>();
2230
-
2231
2431
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for ptr, expected pointer", GetValueType(instance, info[0]));
2232
2432
  return env.Null();
2233
2433
  }
@@ -2256,7 +2456,7 @@ static Napi::Value CreateView(const Napi::CallbackInfo &info)
2256
2456
  static Napi::Value ResetKoffi(const Napi::CallbackInfo &info)
2257
2457
  {
2258
2458
  Napi::Env env = info.Env();
2259
- InstanceData *instance = env.GetInstanceData<InstanceData>();
2459
+ InstanceData *instance = (InstanceData *)info.Data();
2260
2460
 
2261
2461
  if (instance->broker) {
2262
2462
  napi_release_threadsafe_function(instance->broker, napi_tsfn_abort);
@@ -2309,7 +2509,7 @@ void LibraryHolder::Unload()
2309
2509
 
2310
2510
  ValueCast::~ValueCast()
2311
2511
  {
2312
- DeleteReferenceSafe(env, ref);
2512
+ node_api_delete_reference(env, ref);
2313
2513
  }
2314
2514
 
2315
2515
  FunctionInfo::~FunctionInfo()
@@ -2338,16 +2538,15 @@ InstanceMemory::~InstanceMemory()
2338
2538
  #endif
2339
2539
  }
2340
2540
 
2341
- static void RegisterPrimitiveType(Napi::Env env, Napi::Object map, std::initializer_list<const char *> names,
2541
+ static void RegisterPrimitiveType(InstanceData *instance, Napi::Object map, std::initializer_list<const char *> names,
2342
2542
  PrimitiveKind primitive, int32_t size, int16_t align, const char *ref = nullptr)
2343
2543
  {
2344
2544
  K_ASSERT(names.size() > 0);
2345
2545
  K_ASSERT(align <= size);
2346
2546
 
2347
- InstanceData *instance = env.GetInstanceData<InstanceData>();
2348
-
2349
2547
  TypeInfo *type = instance->types.AppendDefault();
2350
2548
 
2549
+ type->instance = instance;
2351
2550
  type->name = *names.begin();
2352
2551
 
2353
2552
  type->primitive = primitive;
@@ -2369,7 +2568,7 @@ static void RegisterPrimitiveType(Napi::Env env, Napi::Object map, std::initiali
2369
2568
  K_ASSERT(type->ref.type);
2370
2569
  }
2371
2570
 
2372
- Napi::Value wrapper = WrapType(env, type);
2571
+ napi_value wrapper = WrapType(instance, type);
2373
2572
 
2374
2573
  for (const char *name: names) {
2375
2574
  bool inserted;
@@ -2428,12 +2627,12 @@ static bool CanCallNapiGetBufferInfoDirectly(const napi_node_version &node, uint
2428
2627
  return false;
2429
2628
  }
2430
2629
 
2431
- static bool CanReferencePrimitiveValues(const napi_node_version &node, uint32_t napi)
2630
+ static bool CanReferencePrimitiveValues(const napi_node_version &, uint32_t napi)
2432
2631
  {
2433
2632
  return napi >= 10;
2434
2633
  }
2435
2634
 
2436
- static bool CanDeleteReferenceInFinalizer(const napi_node_version &node, uint32_t napi)
2635
+ static bool CanDeleteReferenceInFinalizer(const napi_node_version &node, uint32_t)
2437
2636
  {
2438
2637
  if (node.major >= 24)
2439
2638
  return true;
@@ -2451,12 +2650,12 @@ static bool CanDeleteReferenceInFinalizer(const napi_node_version &node, uint32_
2451
2650
  return false;
2452
2651
  }
2453
2652
 
2454
- static napi_value CreateFunction(napi_env env, napi_callback native, const char *name = nullptr)
2653
+ static napi_value CreateFunction(InstanceData *instance, napi_callback native, const char *name = nullptr)
2455
2654
  {
2456
- napi_value func;
2655
+ Napi::Env env = instance->env;
2457
2656
 
2458
- napi_status status = napi_create_function(env, name, NAPI_AUTO_LENGTH, native, nullptr, &func);
2459
- K_ASSERT(status == napi_ok);
2657
+ napi_value func;
2658
+ NAPI_OK(napi_create_function(env, name, NAPI_AUTO_LENGTH, native, instance, &func));
2460
2659
 
2461
2660
  return func;
2462
2661
  }
@@ -2508,6 +2707,21 @@ static Napi::Object InitModule(Napi::Env env, Napi::Object exports)
2508
2707
  // errors out (or even asserts) if it gets called in a finalizer. In this case,
2509
2708
  // use experimental API to try to run it later.
2510
2709
  node_api_post_finalizer = SYMBOL(node_api_post_finalizer);
2710
+
2711
+ if (node_api_post_finalizer) {
2712
+ node_api_delete_reference = [](node_api_basic_env env, napi_ref ref) {
2713
+ node_api_post_finalizer((napi_env)env, [](napi_env env, void *data, void *) {
2714
+ napi_ref ref = (napi_ref)data;
2715
+ napi_delete_reference(env, ref);
2716
+ }, (void *)ref, nullptr);
2717
+
2718
+ return napi_ok;
2719
+ };
2720
+ } else {
2721
+ node_api_delete_reference = napi_delete_reference;
2722
+ }
2723
+ } else {
2724
+ node_api_delete_reference = napi_delete_reference;
2511
2725
  }
2512
2726
 
2513
2727
  node_api_create_object_with_properties = SYMBOL(node_api_create_object_with_properties);
@@ -2520,85 +2734,102 @@ static Napi::Object InitModule(Napi::Env env, Napi::Object exports)
2520
2734
  K_CRITICAL(instance, "Failed to initialize Koffi");
2521
2735
 
2522
2736
  instance->env = env;
2523
- env.SetInstanceData(instance);
2524
2737
 
2525
2738
  #if defined(__clang__)
2526
2739
  // First call to napi_create_double() does some weird stuff I can't explain
2527
2740
  // in clang-cl builds. I don't like this... but this fixes it, somehow ><
2528
- Napi::Number::New(env, 0.0);
2741
+ NewFloat(env, 0.0);
2529
2742
  #endif
2530
2743
 
2531
- exports.Set("config", Napi::Function::New(env, GetSetConfig, "config"));
2532
- exports.Set("stats", Napi::Function::New(env, GetStats, "stats"));
2533
-
2534
- exports.Set("struct", Napi::Function::New(env, CreatePaddedStructType, "struct"));
2535
- exports.Set("pack", Napi::Function::New(env, CreatePackedStructType, "pack"));
2536
- exports.Set("union", Napi::Function::New(env, CreateUnionType, "union"));
2537
- exports.Set("Union", Napi::Function::New(env, InstantiateUnion, "Union"));
2538
- exports.Set("opaque", Napi::Function::New(env, CreateOpaqueType, "opaque"));
2539
- exports.Set("pointer", Napi::Function::New(env, CreatePointerType, "pointer"));
2540
- exports.Set("array", Napi::Function::New(env, CreateArrayType, "array"));
2541
- exports.Set("proto", Napi::Function::New(env, CreateFunctionType, "proto"));
2542
- exports.Set("alias", Napi::Function::New(env, CreateTypeAlias, "alias"));
2543
- exports.Set("enumeration", Napi::Function::New(env, CreateEnumType, "enumeration"));
2544
-
2545
- exports.Set("type", Napi::Function::New(env, GetResolvedType, "type"));
2744
+ exports.Set("config", Napi::Function::New(env, GetSetConfig, "config", instance));
2745
+ exports.Set("stats", Napi::Function::New(env, GetStats, "stats", instance));
2746
+
2747
+ exports.Set("struct", Napi::Function::New(env, CreatePaddedStructType, "struct", instance));
2748
+ exports.Set("pack", Napi::Function::New(env, CreatePackedStructType, "pack", instance));
2749
+ exports.Set("union", Napi::Function::New(env, CreateUnionType, "union", instance));
2750
+ exports.Set("Union", Napi::Function::New(env, InstantiateUnion, "Union", instance));
2751
+ exports.Set("opaque", Napi::Function::New(env, CreateOpaqueType, "opaque", instance));
2752
+ exports.Set("pointer", Napi::Function::New(env, CreatePointerType, "pointer", instance));
2753
+ exports.Set("array", Napi::Function::New(env, CreateArrayType, "array", instance));
2754
+ exports.Set("proto", Napi::Function::New(env, CreateFunctionType, "proto", instance));
2755
+ exports.Set("alias", Napi::Function::New(env, CreateTypeAlias, "alias", instance));
2756
+ exports.Set("enumeration", Napi::Function::New(env, CreateEnumType, "enumeration", instance));
2757
+
2758
+ exports.Set("type", Napi::Function::New(env, GetResolvedType, "type", instance));
2546
2759
  #if defined(EXTERNAL_TYPES)
2547
- exports.Set("introspect", Napi::Function::New(env, GetTypeDefinition, "introspect"));
2760
+ exports.Set("introspect", Napi::Function::New(env, GetTypeDefinition, "introspect", instance));
2548
2761
  #endif
2549
2762
 
2550
- exports.Set("load", Napi::Function::New(env, LoadSharedLibrary, "load"));
2763
+ exports.Set("load", Napi::Function::New(env, LoadSharedLibrary, "load", instance));
2551
2764
 
2552
- exports.Set("in", Napi::Function::New(env, MarkIn, "in"));
2553
- exports.Set("out", Napi::Function::New(env, MarkOut, "out"));
2554
- exports.Set("inout", Napi::Function::New(env, MarkInOut, "inout"));
2765
+ exports.Set("in", Napi::Function::New(env, MarkIn, "in", instance));
2766
+ exports.Set("out", Napi::Function::New(env, MarkOut, "out", instance));
2767
+ exports.Set("inout", Napi::Function::New(env, MarkInOut, "inout", instance));
2555
2768
 
2556
- exports.Set("disposable", Napi::Function::New(env, CreateDisposableType, "disposable"));
2557
- exports.Set("alloc", Napi::Function::New(env, CallAlloc, "alloc"));
2558
- exports.Set("free", Napi::Function::New(env, CallFree, "free"));
2769
+ exports.Set("disposable", Napi::Function::New(env, CreateDisposableType, "disposable", instance));
2770
+ exports.Set("alloc", Napi::Function::New(env, CallAlloc, "alloc", instance));
2771
+ exports.Set("free", Napi::Function::New(env, CallFree, "free", instance));
2559
2772
 
2560
- exports.Set("register", Napi::Function::New(env, RegisterCallback, "register"));
2561
- exports.Set("unregister", Napi::Function::New(env, UnregisterCallback, "unregister"));
2773
+ exports.Set("register", Napi::Function::New(env, RegisterCallback, "register", instance));
2774
+ exports.Set("unregister", Napi::Function::New(env, UnregisterCallback, "unregister", instance));
2562
2775
 
2563
- exports.Set("as", Napi::Function::New(env, CastValue, "as"));
2564
- exports.Set("address", Napi::Function::New(env, GetPointerAddress, "address"));
2565
- exports.Set("call", Napi::Function::New(env, CallPointerSync, "call"));
2566
- exports.Set("encode", Napi::Function::New(env, EncodeValue, "encode"));
2567
- exports.Set("view", Napi::Function::New(env, CreateView, "view"));
2776
+ exports.Set("as", Napi::Function::New(env, CastValue, "as", instance));
2777
+ exports.Set("address", Napi::Function::New(env, GetPointerAddress, "address", instance));
2778
+ exports.Set("call", Napi::Function::New(env, CallPointerSync, "call", instance));
2779
+ exports.Set("encode", Napi::Function::New(env, EncodeValue, "encode", instance));
2780
+ exports.Set("view", Napi::Function::New(env, CreateView, "view", instance));
2568
2781
 
2569
2782
  {
2570
- Napi::Function decode = Napi::Function::New(env, DecodeValue, "decode");
2571
-
2572
- decode.Set("char", CreateFunction(env, [](napi_env env, napi_callback_info info) { return DecodeInteger<char>(env, info); }, "char"));
2573
- decode.Set("uchar", CreateFunction(env, [](napi_env env, napi_callback_info info) { return DecodeInteger<unsigned char>(env, info); }, "uchar"));
2574
- decode.Set("short", CreateFunction(env, [](napi_env env, napi_callback_info info) { return DecodeInteger<short>(env, info); }, "short"));
2575
- decode.Set("ushort", CreateFunction(env, [](napi_env env, napi_callback_info info) { return DecodeInteger<unsigned short>(env, info); }, "ushort"));
2576
- decode.Set("int", CreateFunction(env, [](napi_env env, napi_callback_info info) { return DecodeInteger<int>(env, info); }, "int"));
2577
- decode.Set("uint", CreateFunction(env, [](napi_env env, napi_callback_info info) { return DecodeInteger<unsigned int>(env, info); }, "uint"));
2578
- decode.Set("long", CreateFunction(env, [](napi_env env, napi_callback_info info) { return DecodeInteger<long>(env, info); }, "long"));
2579
- decode.Set("ulong", CreateFunction(env, [](napi_env env, napi_callback_info info) { return DecodeInteger<unsigned long>(env, info); }, "ulong"));
2580
- decode.Set("longlong", CreateFunction(env, [](napi_env env, napi_callback_info info) { return DecodeInteger<long long>(env, info); }, "longlong"));
2581
- decode.Set("ulonglong", CreateFunction(env, [](napi_env env, napi_callback_info info) { return DecodeInteger<unsigned long long>(env, info); }, "ulonglong"));
2582
- decode.Set("int8", CreateFunction(env, [](napi_env env, napi_callback_info info) { return DecodeInteger<int8_t>(env, info); }, "int8"));
2583
- decode.Set("uint8", CreateFunction(env, [](napi_env env, napi_callback_info info) { return DecodeInteger<uint8_t>(env, info); }, "uint8"));
2584
- decode.Set("int16", CreateFunction(env, [](napi_env env, napi_callback_info info) { return DecodeInteger<int16_t>(env, info); }, "int16"));
2585
- decode.Set("uint16", CreateFunction(env, [](napi_env env, napi_callback_info info) { return DecodeInteger<uint16_t>(env, info); }, "uint16"));
2586
- decode.Set("int32", CreateFunction(env, [](napi_env env, napi_callback_info info) { return DecodeInteger<int32_t>(env, info); }, "int32"));
2587
- decode.Set("uint32", CreateFunction(env, [](napi_env env, napi_callback_info info) { return DecodeInteger<uint32_t>(env, info); }, "uint32"));
2588
- decode.Set("int64", CreateFunction(env, [](napi_env env, napi_callback_info info) { return DecodeInteger<int64_t>(env, info); }, "int64"));
2589
- decode.Set("uint64", CreateFunction(env, [](napi_env env, napi_callback_info info) { return DecodeInteger<uint64_t>(env, info); }, "uint64"));
2590
- decode.Set("float", CreateFunction(env, DecodeFloat, "float"));
2591
- decode.Set("double", CreateFunction(env, DecodeDouble, "double"));
2592
- decode.Set("string", CreateFunction(env, DecodeString, "string"));
2593
- decode.Set("string16", CreateFunction(env, DecodeString16, "string16"));
2594
- decode.Set("string32", CreateFunction(env, DecodeString32, "string32"));
2783
+ Napi::Function decode = Napi::Function::New(env, DecodeValue, "decode", instance);
2784
+
2785
+ decode.Set("char", CreateFunction(instance, [](napi_env env, napi_callback_info info) { return DecodeInteger<char>(env, info); }, "char"));
2786
+ decode.Set("uchar", CreateFunction(instance, [](napi_env env, napi_callback_info info) { return DecodeInteger<unsigned char>(env, info); }, "uchar"));
2787
+ decode.Set("short", CreateFunction(instance, [](napi_env env, napi_callback_info info) { return DecodeInteger<short>(env, info); }, "short"));
2788
+ decode.Set("ushort", CreateFunction(instance, [](napi_env env, napi_callback_info info) { return DecodeInteger<unsigned short>(env, info); }, "ushort"));
2789
+ decode.Set("int", CreateFunction(instance, [](napi_env env, napi_callback_info info) { return DecodeInteger<int>(env, info); }, "int"));
2790
+ decode.Set("uint", CreateFunction(instance, [](napi_env env, napi_callback_info info) { return DecodeInteger<unsigned int>(env, info); }, "uint"));
2791
+ decode.Set("long", CreateFunction(instance, [](napi_env env, napi_callback_info info) { return DecodeInteger<long>(env, info); }, "long"));
2792
+ decode.Set("ulong", CreateFunction(instance, [](napi_env env, napi_callback_info info) { return DecodeInteger<unsigned long>(env, info); }, "ulong"));
2793
+ decode.Set("longlong", CreateFunction(instance, [](napi_env env, napi_callback_info info) { return DecodeInteger<long long>(env, info); }, "longlong"));
2794
+ decode.Set("ulonglong", CreateFunction(instance, [](napi_env env, napi_callback_info info) { return DecodeInteger<unsigned long long>(env, info); }, "ulonglong"));
2795
+ decode.Set("int8", CreateFunction(instance, [](napi_env env, napi_callback_info info) { return DecodeInteger<int8_t>(env, info); }, "int8"));
2796
+ decode.Set("uint8", CreateFunction(instance, [](napi_env env, napi_callback_info info) { return DecodeInteger<uint8_t>(env, info); }, "uint8"));
2797
+ decode.Set("int16", CreateFunction(instance, [](napi_env env, napi_callback_info info) { return DecodeInteger<int16_t>(env, info); }, "int16"));
2798
+ decode.Set("int16le", CreateFunction(instance, [](napi_env env, napi_callback_info info) { return DecodeIntegerLE<int16_t>(env, info); }, "int16le"));
2799
+ decode.Set("int16be", CreateFunction(instance, [](napi_env env, napi_callback_info info) { return DecodeIntegerBE<int16_t>(env, info); }, "int16be"));
2800
+ decode.Set("uint16", CreateFunction(instance, [](napi_env env, napi_callback_info info) { return DecodeInteger<uint16_t>(env, info); }, "uint16"));
2801
+ decode.Set("uint16le", CreateFunction(instance, [](napi_env env, napi_callback_info info) { return DecodeIntegerLE<uint16_t>(env, info); }, "uint16le"));
2802
+ decode.Set("uint16be", CreateFunction(instance, [](napi_env env, napi_callback_info info) { return DecodeIntegerBE<uint16_t>(env, info); }, "uint16be"));
2803
+ decode.Set("int32", CreateFunction(instance, [](napi_env env, napi_callback_info info) { return DecodeInteger<int32_t>(env, info); }, "int32"));
2804
+ decode.Set("int32le", CreateFunction(instance, [](napi_env env, napi_callback_info info) { return DecodeIntegerLE<int32_t>(env, info); }, "int32le"));
2805
+ decode.Set("int32be", CreateFunction(instance, [](napi_env env, napi_callback_info info) { return DecodeIntegerBE<int32_t>(env, info); }, "int32be"));
2806
+ decode.Set("uint32", CreateFunction(instance, [](napi_env env, napi_callback_info info) { return DecodeInteger<uint32_t>(env, info); }, "uint32"));
2807
+ decode.Set("uint32le", CreateFunction(instance, [](napi_env env, napi_callback_info info) { return DecodeIntegerLE<uint32_t>(env, info); }, "uint32le"));
2808
+ decode.Set("uint32be", CreateFunction(instance, [](napi_env env, napi_callback_info info) { return DecodeIntegerBE<uint32_t>(env, info); }, "uint32be"));
2809
+ decode.Set("int64", CreateFunction(instance, [](napi_env env, napi_callback_info info) { return DecodeInteger<int64_t>(env, info); }, "int64"));
2810
+ decode.Set("int64le", CreateFunction(instance, [](napi_env env, napi_callback_info info) { return DecodeIntegerLE<int64_t>(env, info); }, "int64le"));
2811
+ decode.Set("int64be", CreateFunction(instance, [](napi_env env, napi_callback_info info) { return DecodeIntegerBE<int64_t>(env, info); }, "int64be"));
2812
+ decode.Set("uint64", CreateFunction(instance, [](napi_env env, napi_callback_info info) { return DecodeInteger<uint64_t>(env, info); }, "uint64"));
2813
+ decode.Set("uint64le", CreateFunction(instance, [](napi_env env, napi_callback_info info) { return DecodeIntegerLE<uint64_t>(env, info); }, "uint64le"));
2814
+ decode.Set("uint64be", CreateFunction(instance, [](napi_env env, napi_callback_info info) { return DecodeIntegerBE<uint64_t>(env, info); }, "uint64be"));
2815
+ decode.Set("float", CreateFunction(instance, DecodeFloat, "float"));
2816
+ decode.Set("double", CreateFunction(instance, DecodeDouble, "double"));
2817
+ decode.Set("string", CreateFunction(instance, DecodeString, "string"));
2818
+ decode.Set("string16", CreateFunction(instance, DecodeString16, "string16"));
2819
+ decode.Set("string32", CreateFunction(instance, DecodeString32, "string32"));
2820
+ if constexpr (K_SIZE(wchar_t) == 2) {
2821
+ decode.Set("wstring", CreateFunction(instance, DecodeString16, "wstring"));
2822
+ } else if constexpr (K_SIZE(wchar_t) == 4) {
2823
+ decode.Set("wstring", CreateFunction(instance, DecodeString32, "wstring"));
2824
+ }
2825
+ static_assert(K_SIZE(wchar_t) == 2 || K_SIZE(wchar_t) == 4);
2595
2826
 
2596
2827
  exports.Set("decode", decode);
2597
2828
  }
2598
2829
 
2599
- exports.Set("reset", Napi::Function::New(env, ResetKoffi, "reset"));
2830
+ exports.Set("reset", Napi::Function::New(env, ResetKoffi, "reset", instance));
2600
2831
 
2601
- exports.Set("errno", Napi::Function::New(env, GetOrSetErrNo, "errno"));
2832
+ exports.Set("errno", Napi::Function::New(env, GetOrSetErrNo, "errno", instance));
2602
2833
 
2603
2834
  // Export useful OS info
2604
2835
  {
@@ -2615,21 +2846,21 @@ static Napi::Object InitModule(Napi::Env env, Napi::Object exports)
2615
2846
  }
2616
2847
 
2617
2848
  #if defined(_WIN32)
2618
- exports.Set("extension", Napi::String::New(env, ".dll"));
2849
+ exports.Set("extension", NewString(env, ".dll"));
2619
2850
  #elif defined(__APPLE__)
2620
- exports.Set("extension", Napi::String::New(env, ".dylib"));
2851
+ exports.Set("extension", NewString(env, ".dylib"));
2621
2852
  #else
2622
- exports.Set("extension", Napi::String::New(env, ".so"));
2853
+ exports.Set("extension", NewString(env, ".so"));
2623
2854
  #endif
2624
2855
 
2625
2856
  // Init object classes and symbols
2626
2857
  {
2627
2858
  instance->object_constructor = Napi::Persistent(env.RunScript("Object.prototype").As<Napi::Object>());
2628
- instance->construct_lib = Napi::Persistent(LibraryHandle::InitClass(env));
2859
+ instance->construct_lib = Napi::Persistent(LibraryHandle::InitClass(instance));
2629
2860
  #if !defined(EXTERNAL_TYPES)
2630
- instance->construct_type = Napi::Persistent(TypeObject::InitClass(env));
2861
+ instance->construct_type = Napi::Persistent(TypeObject::InitClass(instance));
2631
2862
  #endif
2632
- instance->construct_poll = Napi::Persistent(PollHandle::InitClass(env));
2863
+ instance->construct_poll = Napi::Persistent(PollHandle::InitClass(instance));
2633
2864
  instance->active_symbol = Napi::Persistent(Napi::Symbol::New(env, "active"));
2634
2865
 
2635
2866
  exports.Set("LibraryHandle", instance->construct_lib.Value());
@@ -2643,58 +2874,59 @@ static Napi::Object InitModule(Napi::Env env, Napi::Object exports)
2643
2874
  Napi::Object types = Napi::Object::New(env);
2644
2875
  exports.Set("types", types);
2645
2876
 
2646
- RegisterPrimitiveType(env, types, {"void"}, PrimitiveKind::Void, 0, 0);
2647
- RegisterPrimitiveType(env, types, {"bool"}, PrimitiveKind::Bool, K_SIZE(bool), alignof(bool));
2648
- RegisterPrimitiveType(env, types, {"int8_t", "int8"}, PrimitiveKind::Int8, 1, 1);
2649
- RegisterPrimitiveType(env, types, {"uint8_t", "uint8"}, PrimitiveKind::UInt8, 1, 1);
2650
- RegisterPrimitiveType(env, types, {"char"}, PrimitiveKind::Int8, 1, 1);
2651
- RegisterPrimitiveType(env, types, {"unsigned char", "uchar"}, PrimitiveKind::UInt8, 1, 1);
2652
- RegisterPrimitiveType(env, types, {"char16_t", "char16"}, PrimitiveKind::Int16, 2, 2);
2653
- RegisterPrimitiveType(env, types, {"char32_t", "char32"}, PrimitiveKind::Int32, 4, 4);
2654
- if (K_SIZE(wchar_t) == 2) {
2655
- RegisterPrimitiveType(env, types, {"wchar_t", "wchar"}, PrimitiveKind::Int16, 2, 2);
2656
- } else if (K_SIZE(wchar_t) == 4) {
2657
- RegisterPrimitiveType(env, types, {"wchar_t", "wchar"}, PrimitiveKind::Int32, 4, 4);
2658
- }
2659
- RegisterPrimitiveType(env, types, {"int16_t", "int16"}, PrimitiveKind::Int16, 2, 2);
2660
- RegisterPrimitiveType(env, types, {"int16_le_t", "int16_le"}, GetLittleEndianPrimitive(PrimitiveKind::Int16), 2, 2);
2661
- RegisterPrimitiveType(env, types, {"int16_be_t", "int16_be"}, GetBigEndianPrimitive(PrimitiveKind::Int16), 2, 2);
2662
- RegisterPrimitiveType(env, types, {"uint16_t", "uint16"}, PrimitiveKind::UInt16, 2, 2);
2663
- RegisterPrimitiveType(env, types, {"uint16_le_t", "uint16_le"}, GetLittleEndianPrimitive(PrimitiveKind::UInt16), 2, 2);
2664
- RegisterPrimitiveType(env, types, {"uint16_be_t", "uint16_be"}, GetBigEndianPrimitive(PrimitiveKind::UInt16), 2, 2);
2665
- RegisterPrimitiveType(env, types, {"short"}, PrimitiveKind::Int16, 2, 2);
2666
- RegisterPrimitiveType(env, types, {"unsigned short", "ushort"}, PrimitiveKind::UInt16, 2, 2);
2667
- RegisterPrimitiveType(env, types, {"int32_t", "int32"}, PrimitiveKind::Int32, 4, 4);
2668
- RegisterPrimitiveType(env, types, {"int32_le_t", "int32_le"}, GetLittleEndianPrimitive(PrimitiveKind::Int32), 4, 4);
2669
- RegisterPrimitiveType(env, types, {"int32_be_t", "int32_be"}, GetBigEndianPrimitive(PrimitiveKind::Int32), 4, 4);
2670
- RegisterPrimitiveType(env, types, {"uint32_t", "uint32"}, PrimitiveKind::UInt32, 4, 4);
2671
- RegisterPrimitiveType(env, types, {"uint32_le_t", "uint32_le"}, GetLittleEndianPrimitive(PrimitiveKind::UInt32), 4, 4);
2672
- RegisterPrimitiveType(env, types, {"uint32_be_t", "uint32_be"}, GetBigEndianPrimitive(PrimitiveKind::UInt32), 4, 4);
2673
- RegisterPrimitiveType(env, types, {"int"}, PrimitiveKind::Int32, 4, 4);
2674
- RegisterPrimitiveType(env, types, {"unsigned int", "uint"}, PrimitiveKind::UInt32, 4, 4);
2675
- RegisterPrimitiveType(env, types, {"int64_t", "int64"}, PrimitiveKind::Int64, 8, alignof(int64_t));
2676
- RegisterPrimitiveType(env, types, {"int64_le_t", "int64_le"}, GetLittleEndianPrimitive(PrimitiveKind::Int64), 8, alignof(int64_t));
2677
- RegisterPrimitiveType(env, types, {"int64_be_t", "int64_be"}, GetBigEndianPrimitive(PrimitiveKind::Int64), 8, alignof(int64_t));
2678
- RegisterPrimitiveType(env, types, {"uint64_t", "uint64"}, PrimitiveKind::UInt64, 8, alignof(int64_t));
2679
- RegisterPrimitiveType(env, types, {"uint64_le_t", "uint64_le"}, GetLittleEndianPrimitive(PrimitiveKind::UInt64), 8, alignof(int64_t));
2680
- RegisterPrimitiveType(env, types, {"uint64_be_t", "uint64_be"}, GetBigEndianPrimitive(PrimitiveKind::UInt64), 8, alignof(int64_t));
2681
- RegisterPrimitiveType(env, types, {"intptr_t", "intptr"}, GetSignPrimitive(K_SIZE(intptr_t), true), K_SIZE(intptr_t), alignof(intptr_t));
2682
- RegisterPrimitiveType(env, types, {"uintptr_t", "uintptr"}, GetSignPrimitive(K_SIZE(intptr_t), false), K_SIZE(intptr_t), alignof(intptr_t));
2683
- RegisterPrimitiveType(env, types, {"size_t"}, GetSignPrimitive(K_SIZE(size_t), false), K_SIZE(size_t), alignof(size_t));
2684
- RegisterPrimitiveType(env, types, {"long"}, GetSignPrimitive(K_SIZE(long), true), K_SIZE(long), alignof(long));
2685
- RegisterPrimitiveType(env, types, {"unsigned long", "ulong"}, GetSignPrimitive(K_SIZE(long), false), K_SIZE(long), alignof(long));
2686
- RegisterPrimitiveType(env, types, {"long long", "longlong"}, PrimitiveKind::Int64, K_SIZE(int64_t), alignof(int64_t));
2687
- RegisterPrimitiveType(env, types, {"unsigned long long", "ulonglong"}, PrimitiveKind::UInt64, K_SIZE(uint64_t), alignof(uint64_t));
2688
- RegisterPrimitiveType(env, types, {"float", "float32"}, PrimitiveKind::Float32, 4, alignof(float));
2689
- RegisterPrimitiveType(env, types, {"double", "float64"}, PrimitiveKind::Float64, 8, alignof(double));
2690
- RegisterPrimitiveType(env, types, {"char *", "str", "string"}, PrimitiveKind::String, K_SIZE(void *), alignof(void *), "char");
2691
- RegisterPrimitiveType(env, types, {"char16_t *", "char16 *", "str16", "string16"}, PrimitiveKind::String16, K_SIZE(void *), alignof(void *), "char16_t");
2692
- RegisterPrimitiveType(env, types, {"char32_t *", "char32 *", "str32", "string32"}, PrimitiveKind::String32, K_SIZE(void *), alignof(void *), "char32_t");
2693
- if (K_SIZE(wchar_t) == 2) {
2694
- RegisterPrimitiveType(env, types, {"wchar_t *", "wchar *"}, PrimitiveKind::String16, K_SIZE(void *), alignof(void *), "wchar_t");
2695
- } else if (K_SIZE(wchar_t) == 4) {
2696
- RegisterPrimitiveType(env, types, {"wchar_t *", "wchar *"}, PrimitiveKind::String32, K_SIZE(void *), alignof(void *), "wchar_t");
2877
+ RegisterPrimitiveType(instance, types, {"void"}, PrimitiveKind::Void, 0, 0);
2878
+ RegisterPrimitiveType(instance, types, {"bool"}, PrimitiveKind::Bool, K_SIZE(bool), alignof(bool));
2879
+ RegisterPrimitiveType(instance, types, {"int8_t", "int8"}, PrimitiveKind::Int8, 1, 1);
2880
+ RegisterPrimitiveType(instance, types, {"uint8_t", "uint8"}, PrimitiveKind::UInt8, 1, 1);
2881
+ RegisterPrimitiveType(instance, types, {"char"}, PrimitiveKind::Int8, 1, 1);
2882
+ RegisterPrimitiveType(instance, types, {"unsigned char", "uchar"}, PrimitiveKind::UInt8, 1, 1);
2883
+ RegisterPrimitiveType(instance, types, {"char16_t", "char16"}, PrimitiveKind::Int16, 2, 2);
2884
+ RegisterPrimitiveType(instance, types, {"char32_t", "char32"}, PrimitiveKind::Int32, 4, 4);
2885
+ if constexpr (K_SIZE(wchar_t) == 2) {
2886
+ RegisterPrimitiveType(instance, types, {"wchar_t", "wchar"}, PrimitiveKind::Int16, 2, 2);
2887
+ } else if constexpr (K_SIZE(wchar_t) == 4) {
2888
+ RegisterPrimitiveType(instance, types, {"wchar_t", "wchar"}, PrimitiveKind::Int32, 4, 4);
2889
+ }
2890
+ RegisterPrimitiveType(instance, types, {"int16_t", "int16"}, PrimitiveKind::Int16, 2, 2);
2891
+ RegisterPrimitiveType(instance, types, {"int16_le_t", "int16_le"}, GetLittleEndianPrimitive(PrimitiveKind::Int16), 2, 2);
2892
+ RegisterPrimitiveType(instance, types, {"int16_be_t", "int16_be"}, GetBigEndianPrimitive(PrimitiveKind::Int16), 2, 2);
2893
+ RegisterPrimitiveType(instance, types, {"uint16_t", "uint16"}, PrimitiveKind::UInt16, 2, 2);
2894
+ RegisterPrimitiveType(instance, types, {"uint16_le_t", "uint16_le"}, GetLittleEndianPrimitive(PrimitiveKind::UInt16), 2, 2);
2895
+ RegisterPrimitiveType(instance, types, {"uint16_be_t", "uint16_be"}, GetBigEndianPrimitive(PrimitiveKind::UInt16), 2, 2);
2896
+ RegisterPrimitiveType(instance, types, {"short"}, PrimitiveKind::Int16, 2, 2);
2897
+ RegisterPrimitiveType(instance, types, {"unsigned short", "ushort"}, PrimitiveKind::UInt16, 2, 2);
2898
+ RegisterPrimitiveType(instance, types, {"int32_t", "int32"}, PrimitiveKind::Int32, 4, 4);
2899
+ RegisterPrimitiveType(instance, types, {"int32_le_t", "int32_le"}, GetLittleEndianPrimitive(PrimitiveKind::Int32), 4, 4);
2900
+ RegisterPrimitiveType(instance, types, {"int32_be_t", "int32_be"}, GetBigEndianPrimitive(PrimitiveKind::Int32), 4, 4);
2901
+ RegisterPrimitiveType(instance, types, {"uint32_t", "uint32"}, PrimitiveKind::UInt32, 4, 4);
2902
+ RegisterPrimitiveType(instance, types, {"uint32_le_t", "uint32_le"}, GetLittleEndianPrimitive(PrimitiveKind::UInt32), 4, 4);
2903
+ RegisterPrimitiveType(instance, types, {"uint32_be_t", "uint32_be"}, GetBigEndianPrimitive(PrimitiveKind::UInt32), 4, 4);
2904
+ RegisterPrimitiveType(instance, types, {"int"}, PrimitiveKind::Int32, 4, 4);
2905
+ RegisterPrimitiveType(instance, types, {"unsigned int", "uint"}, PrimitiveKind::UInt32, 4, 4);
2906
+ RegisterPrimitiveType(instance, types, {"int64_t", "int64"}, PrimitiveKind::Int64, 8, alignof(int64_t));
2907
+ RegisterPrimitiveType(instance, types, {"int64_le_t", "int64_le"}, GetLittleEndianPrimitive(PrimitiveKind::Int64), 8, alignof(int64_t));
2908
+ RegisterPrimitiveType(instance, types, {"int64_be_t", "int64_be"}, GetBigEndianPrimitive(PrimitiveKind::Int64), 8, alignof(int64_t));
2909
+ RegisterPrimitiveType(instance, types, {"uint64_t", "uint64"}, PrimitiveKind::UInt64, 8, alignof(int64_t));
2910
+ RegisterPrimitiveType(instance, types, {"uint64_le_t", "uint64_le"}, GetLittleEndianPrimitive(PrimitiveKind::UInt64), 8, alignof(int64_t));
2911
+ RegisterPrimitiveType(instance, types, {"uint64_be_t", "uint64_be"}, GetBigEndianPrimitive(PrimitiveKind::UInt64), 8, alignof(int64_t));
2912
+ RegisterPrimitiveType(instance, types, {"intptr_t", "intptr"}, GetSignPrimitive(K_SIZE(intptr_t), true), K_SIZE(intptr_t), alignof(intptr_t));
2913
+ RegisterPrimitiveType(instance, types, {"uintptr_t", "uintptr"}, GetSignPrimitive(K_SIZE(intptr_t), false), K_SIZE(intptr_t), alignof(intptr_t));
2914
+ RegisterPrimitiveType(instance, types, {"size_t"}, GetSignPrimitive(K_SIZE(size_t), false), K_SIZE(size_t), alignof(size_t));
2915
+ RegisterPrimitiveType(instance, types, {"long"}, GetSignPrimitive(K_SIZE(long), true), K_SIZE(long), alignof(long));
2916
+ RegisterPrimitiveType(instance, types, {"unsigned long", "ulong"}, GetSignPrimitive(K_SIZE(long), false), K_SIZE(long), alignof(long));
2917
+ RegisterPrimitiveType(instance, types, {"long long", "longlong"}, PrimitiveKind::Int64, K_SIZE(int64_t), alignof(int64_t));
2918
+ RegisterPrimitiveType(instance, types, {"unsigned long long", "ulonglong"}, PrimitiveKind::UInt64, K_SIZE(uint64_t), alignof(uint64_t));
2919
+ RegisterPrimitiveType(instance, types, {"float", "float32"}, PrimitiveKind::Float32, 4, alignof(float));
2920
+ RegisterPrimitiveType(instance, types, {"double", "float64"}, PrimitiveKind::Float64, 8, alignof(double));
2921
+ RegisterPrimitiveType(instance, types, {"char *", "str", "string"}, PrimitiveKind::String, K_SIZE(void *), alignof(void *), "char");
2922
+ RegisterPrimitiveType(instance, types, {"char16_t *", "char16 *", "str16", "string16"}, PrimitiveKind::String16, K_SIZE(void *), alignof(void *), "char16_t");
2923
+ RegisterPrimitiveType(instance, types, {"char32_t *", "char32 *", "str32", "string32"}, PrimitiveKind::String32, K_SIZE(void *), alignof(void *), "char32_t");
2924
+ if constexpr (K_SIZE(wchar_t) == 2) {
2925
+ RegisterPrimitiveType(instance, types, {"wchar_t *", "wchar *", "wstring"}, PrimitiveKind::String16, K_SIZE(void *), alignof(void *), "wchar_t");
2926
+ } else if constexpr (K_SIZE(wchar_t) == 4) {
2927
+ RegisterPrimitiveType(instance, types, {"wchar_t *", "wchar *", "wstring"}, PrimitiveKind::String32, K_SIZE(void *), alignof(void *), "wchar_t");
2697
2928
  }
2929
+ static_assert(K_SIZE(wchar_t) == 2 || K_SIZE(wchar_t) == 4);
2698
2930
 
2699
2931
  instance->void_type = instance->types_map.FindValue("void", nullptr);
2700
2932
  instance->char_type = instance->types_map.FindValue("char", nullptr);
@@ -2714,11 +2946,11 @@ static Napi::Object InitModule(Napi::Env env, Napi::Object exports)
2714
2946
 
2715
2947
  node.Set("env", WrapPointer(env, instance->void_type, (napi_env)env));
2716
2948
 
2717
- node.Set("poll", Napi::Function::New(env, &Poll, "poll"));
2949
+ node.Set("poll", Napi::Function::New(env, &Poll, "poll", instance));
2718
2950
  node.Set("PollHandle", instance->construct_poll.Value());
2719
2951
  }
2720
2952
 
2721
- exports.Set("version", Napi::String::New(env, K_STRINGIFY(VERSION)));
2953
+ exports.Set("version", NewString(env, K_STRINGIFY(VERSION)));
2722
2954
 
2723
2955
  #if defined(_WIN32)
2724
2956
  {
@@ -2729,7 +2961,6 @@ static Napi::Object InitModule(Napi::Env env, Napi::Object exports)
2729
2961
  }
2730
2962
  #endif
2731
2963
 
2732
- instance->translate_zero_call = translate_zero_call;
2733
2964
  instance->main_thread_id = std::this_thread::get_id();
2734
2965
 
2735
2966
  napi_add_env_cleanup_hook(env, [](void *udata) {
@@ -2764,7 +2995,7 @@ InstanceData::~InstanceData()
2764
2995
  if (trampoline->instance == this) {
2765
2996
  trampoline->instance = nullptr;
2766
2997
  if (trampoline->func) {
2767
- napi_delete_reference(env, trampoline->func);
2998
+ node_api_delete_reference(env, trampoline->func);
2768
2999
  trampoline->func = nullptr;
2769
3000
  }
2770
3001
  trampoline->state = 0;