koffi 2.8.2 → 2.8.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,10 @@
4
4
 
5
5
  ### Koffi 2.8
6
6
 
7
+ #### Koffi 2.8.3 (2024-04-08)
8
+
9
+ - Use simpler workaround for Node 20.12+ and 21.6+ to avoid excessive memory use
10
+
7
11
  #### Koffi 2.8.2 (2024-04-07)
8
12
 
9
13
  - Support [loading library](functions.md#loading-options) with RTLD_GLOBAL on POSIX platforms
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/index.js CHANGED
@@ -378,8 +378,8 @@ var require_package = __commonJS({
378
378
  "build/dist/src/koffi/package.json"(exports2, module2) {
379
379
  module2.exports = {
380
380
  name: "koffi",
381
- version: "2.8.2",
382
- stable: "2.8.2",
381
+ version: "2.8.3",
382
+ stable: "2.8.3",
383
383
  description: "Fast and simple C FFI (foreign function interface) for Node.js",
384
384
  keywords: [
385
385
  "foreign",
package/indirect.js CHANGED
@@ -378,8 +378,8 @@ var require_package = __commonJS({
378
378
  "build/dist/src/koffi/package.json"(exports2, module2) {
379
379
  module2.exports = {
380
380
  name: "koffi",
381
- version: "2.8.2",
382
- stable: "2.8.2",
381
+ version: "2.8.3",
382
+ stable: "2.8.3",
383
383
  description: "Fast and simple C FFI (foreign function interface) for Node.js",
384
384
  keywords: [
385
385
  "foreign",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koffi",
3
- "version": "2.8.2",
4
- "stable": "2.8.2",
3
+ "version": "2.8.3",
4
+ "stable": "2.8.3",
5
5
  "description": "Fast and simple C FFI (foreign function interface) for Node.js",
6
6
  "keywords": [
7
7
  "foreign",
@@ -2247,7 +2247,6 @@ static InstanceData *CreateInstance()
2247
2247
  instance->main_thread_id = std::this_thread::get_id();
2248
2248
 
2249
2249
  instance->debug = GetDebugFlag("DUMP_CALLS");
2250
- FillRandomSafe(&instance->tag_lower, RG_SIZE(instance->tag_lower));
2251
2250
 
2252
2251
  #ifdef _WIN32
2253
2252
  TEB *teb = GetTEB();
@@ -40,8 +40,10 @@ static const Size MaxParameters = 64;
40
40
  static const Size MaxTrampolines = 8192;
41
41
 
42
42
  enum class PrimitiveKind {
43
- Void,
43
+ // Void is explictly not first so that it is not 0, for reasons related to N-API type tags.
44
+ // Look at TypeInfo definition for more information!
44
45
  Bool,
46
+ Void,
45
47
  Int8,
46
48
  UInt8,
47
49
  Int16,
@@ -68,8 +70,8 @@ enum class PrimitiveKind {
68
70
  Callback
69
71
  };
70
72
  static const char *const PrimitiveKindNames[] = {
71
- "Void",
72
73
  "Bool",
74
+ "Void",
73
75
  "Int8",
74
76
  "UInt8",
75
77
  "Int16",
@@ -123,7 +125,12 @@ static const char *const ArrayHintNames[] = {
123
125
  struct TypeInfo {
124
126
  const char *name;
125
127
 
126
- PrimitiveKind primitive;
128
+ // Make sure primitie ends up as the upper N-API tag value when we cast TypeInfo pointers to
129
+ // napi_type_tag pointers. Yes, I want to do this. We don't do strict aliasing here.
130
+ // N.B. Some node versions don't like when one of the two tag values is 0, so make sure
131
+ // this does not happen! It would happen if primitive is 0 and size is 0. To avoid this
132
+ // situation, PrimitiveKind::Void (the only type with size 0) is explictly not 0.
133
+ alignas(8) PrimitiveKind primitive;
127
134
  int32_t size;
128
135
  int16_t align;
129
136
  uint16_t flags;
@@ -273,10 +280,6 @@ struct InstanceData {
273
280
 
274
281
  bool debug;
275
282
 
276
- uint64_t tag_lower;
277
- BucketArray<napi_type_tag> tags;
278
- HashMap<const void *, napi_type_tag *> tags_map;
279
-
280
283
  const TypeInfo *void_type;
281
284
  const TypeInfo *char_type;
282
285
  const TypeInfo *char16_type;
@@ -29,9 +29,9 @@
29
29
  namespace RG {
30
30
 
31
31
  // Value does not matter, the tag system uses memory addresses
32
- const int TypeInfoMarker = 0xDEADBEEF;
33
- const int CastMarker = 0xDEADBEEF;
34
- const int MagicUnionMarker = 0xDEADBEEF;
32
+ const napi_type_tag TypeInfoMarker = { 0x1cc449675b294374, 0xbb13a50e97dcb017 };
33
+ const napi_type_tag CastMarker = { 0x77f459614a0a412f, 0x80b3dda1341dc8df };
34
+ const napi_type_tag MagicUnionMarker = { 0x5eaf2245526a4c7d, 0x8c86c9ee2b96ffc8 };
35
35
 
36
36
  Napi::Function MagicUnion::InitClass(Napi::Env env, const TypeInfo *type)
37
37
  {
@@ -579,20 +579,20 @@ const char *GetValueType(const InstanceData *instance, Napi::Value value)
579
579
  return "Unknown";
580
580
  }
581
581
 
582
- void SetValueTag(InstanceData *instance, Napi::Value value, const void *marker)
582
+ void SetValueTag(const InstanceData *instance, Napi::Value value, const void *marker)
583
583
  {
584
- RG_ASSERT(marker);
585
-
586
- napi_type_tag *tag = instance->tags_map.FindValue(marker, nullptr);
587
-
588
- if (!tag) {
589
- tag = instance->tags.AppendDefault();
590
-
591
- tag->lower = instance->tag_lower;
592
- tag->upper = (uint64_t)marker;
593
-
594
- instance->tags_map.Set(marker, tag);
595
- }
584
+ static_assert(RG_SIZE(TypeInfo) >= 16);
585
+
586
+ // We used to make a temporary tag on the stack with lower set to a constant value and
587
+ // upper to the pointer address, but this broke in Node 20.12 and Node 21.6 due to ExternalWrapper
588
+ // storing a pointer to the tag and not the tag value itself (which seems wrong, but anyway).
589
+ //
590
+ // Since this is no longer an option, we just type alias whatever marker points to to napi_type_tag.
591
+ // This may seem gross, but we disable strict aliasing anyway, so as long as what marker points
592
+ // to is bigger than 16 bytes and does not change, it works!
593
+ // Which holds true for us: the main thing pointed to is TypeInfo, which is constant and big enough,
594
+ // and the few other markers we use, such as CastMarker, are actual const napi_type_tag structs.
595
+ const napi_type_tag *tag = (const napi_type_tag *)marker;
596
596
 
597
597
  napi_status status = napi_type_tag_object(value.Env(), value, tag);
598
598
  RG_ASSERT(status == napi_ok);
@@ -600,13 +600,11 @@ void SetValueTag(InstanceData *instance, Napi::Value value, const void *marker)
600
600
 
601
601
  bool CheckValueTag(const InstanceData *instance, Napi::Value value, const void *marker)
602
602
  {
603
- RG_ASSERT(marker);
604
-
605
603
  bool match = false;
606
604
 
607
605
  if (!IsNullOrUndefined(value)) {
608
- napi_type_tag tag = { instance->tag_lower, (uint64_t)marker };
609
- napi_check_object_type_tag(value.Env(), value, &tag, &match);
606
+ const napi_type_tag *tag = (const napi_type_tag *)marker;
607
+ napi_check_object_type_tag(value.Env(), value, tag, &match);
610
608
  }
611
609
 
612
610
  return match;
@@ -28,9 +28,9 @@
28
28
 
29
29
  namespace RG {
30
30
 
31
- extern const int TypeInfoMarker;
32
- extern const int CastMarker;
33
- extern const int MagicUnionMarker;
31
+ extern const napi_type_tag TypeInfoMarker;
32
+ extern const napi_type_tag CastMarker;
33
+ extern const napi_type_tag MagicUnionMarker;
34
34
 
35
35
  class MagicUnion: public Napi::ObjectWrap<MagicUnion> {
36
36
  const TypeInfo *type;
@@ -102,7 +102,7 @@ bool CanStoreType(const TypeInfo *type);
102
102
  // Can be slow, only use for error messages
103
103
  const char *GetValueType(const InstanceData *instance, Napi::Value value);
104
104
 
105
- void SetValueTag(InstanceData *instance, Napi::Value value, const void *marker);
105
+ void SetValueTag(const InstanceData *instance, Napi::Value value, const void *marker);
106
106
  bool CheckValueTag(const InstanceData *instance, Napi::Value value, const void *marker);
107
107
 
108
108
  static inline bool IsNullOrUndefined(Napi::Value value)
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file