koffi 2.3.1 → 2.3.2

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 (46) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/doc/misc.md +6 -0
  3. package/package.json +3 -16
  4. package/src/cnoke/LICENSE.txt +165 -0
  5. package/src/cnoke/README.md +97 -0
  6. package/src/cnoke/assets/FindCNoke.cmake +71 -0
  7. package/src/cnoke/assets/win_delay_hook.c +34 -0
  8. package/src/cnoke/cnoke.js +968 -0
  9. package/src/cnoke/package.json +25 -0
  10. package/src/koffi/build/2.3.2/koffi_darwin_arm64.tar.gz +0 -0
  11. package/src/koffi/build/2.3.2/koffi_darwin_x64.tar.gz +0 -0
  12. package/src/koffi/build/2.3.2/koffi_freebsd_arm64.tar.gz +0 -0
  13. package/src/koffi/build/2.3.2/koffi_freebsd_ia32.tar.gz +0 -0
  14. package/src/koffi/build/2.3.2/koffi_freebsd_x64.tar.gz +0 -0
  15. package/src/koffi/build/2.3.2/koffi_linux_arm32hf.tar.gz +0 -0
  16. package/src/koffi/build/2.3.2/koffi_linux_arm64.tar.gz +0 -0
  17. package/src/koffi/build/2.3.2/koffi_linux_ia32.tar.gz +0 -0
  18. package/src/koffi/build/2.3.2/koffi_linux_riscv64hf64.tar.gz +0 -0
  19. package/src/koffi/build/2.3.2/koffi_linux_x64.tar.gz +0 -0
  20. package/src/koffi/build/2.3.2/koffi_openbsd_ia32.tar.gz +0 -0
  21. package/src/koffi/build/2.3.2/koffi_openbsd_x64.tar.gz +0 -0
  22. package/src/koffi/build/2.3.2/koffi_win32_arm64.tar.gz +0 -0
  23. package/src/koffi/build/2.3.2/koffi_win32_ia32.tar.gz +0 -0
  24. package/src/koffi/build/2.3.2/koffi_win32_x64.tar.gz +0 -0
  25. package/src/koffi/src/call.cc +0 -4
  26. package/src/koffi/src/ffi.cc +89 -87
  27. package/src/koffi/src/ffi.hh +13 -7
  28. package/src/koffi/src/index.d.ts +10 -1
  29. package/src/koffi/src/parser.cc +12 -10
  30. package/src/koffi/src/util.cc +80 -35
  31. package/src/koffi/src/util.hh +1 -1
  32. package/src/koffi/build/2.3.1/koffi_darwin_arm64.tar.gz +0 -0
  33. package/src/koffi/build/2.3.1/koffi_darwin_x64.tar.gz +0 -0
  34. package/src/koffi/build/2.3.1/koffi_freebsd_arm64.tar.gz +0 -0
  35. package/src/koffi/build/2.3.1/koffi_freebsd_ia32.tar.gz +0 -0
  36. package/src/koffi/build/2.3.1/koffi_freebsd_x64.tar.gz +0 -0
  37. package/src/koffi/build/2.3.1/koffi_linux_arm32hf.tar.gz +0 -0
  38. package/src/koffi/build/2.3.1/koffi_linux_arm64.tar.gz +0 -0
  39. package/src/koffi/build/2.3.1/koffi_linux_ia32.tar.gz +0 -0
  40. package/src/koffi/build/2.3.1/koffi_linux_riscv64hf64.tar.gz +0 -0
  41. package/src/koffi/build/2.3.1/koffi_linux_x64.tar.gz +0 -0
  42. package/src/koffi/build/2.3.1/koffi_openbsd_ia32.tar.gz +0 -0
  43. package/src/koffi/build/2.3.1/koffi_openbsd_x64.tar.gz +0 -0
  44. package/src/koffi/build/2.3.1/koffi_win32_arm64.tar.gz +0 -0
  45. package/src/koffi/build/2.3.1/koffi_win32_ia32.tar.gz +0 -0
  46. package/src/koffi/build/2.3.1/koffi_win32_x64.tar.gz +0 -0
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "cnoke",
3
+ "version": "3.2.2",
4
+ "description": "Build native Node addons based on CMake, without extra dependency",
5
+ "keywords": [
6
+ "native",
7
+ "addon",
8
+ "cmake",
9
+ "c",
10
+ "c++"
11
+ ],
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "https://github.com/Koromix/rygel.git"
15
+ },
16
+ "author": "Niels Martignène <niels.martignene@protonmail.com>",
17
+ "bin": "cnoke.js",
18
+ "license": "LGPL-3.0",
19
+ "files": [
20
+ "cnoke.js",
21
+ "LICENSE.txt",
22
+ "README.md",
23
+ "assets"
24
+ ]
25
+ }
@@ -1011,10 +1011,6 @@ void CallData::PopOutArguments()
1011
1011
  Napi::Object obj(env, value);
1012
1012
  DecodeObject(obj, out.ptr, out.type);
1013
1013
  }
1014
-
1015
- if (out.type->dispose) {
1016
- out.type->dispose(env, out.type, out.ptr);
1017
- }
1018
1014
  }
1019
1015
  }
1020
1016
 
@@ -122,13 +122,8 @@ static Napi::Value GetSetConfig(const Napi::CallbackInfo &info)
122
122
  return env.Null();
123
123
  }
124
124
 
125
- Size sync_stack_size = instance->sync_stack_size;
126
- Size sync_heap_size = instance->sync_heap_size;
127
- Size async_stack_size = instance->async_stack_size;
128
- Size async_heap_size = instance->async_heap_size;
129
- int resident_async_pools = instance->resident_async_pools;
130
- int max_async_calls = resident_async_pools + instance->max_temporaries;
131
- Size max_type_size = instance->max_type_size;
125
+ decltype(instance->config) new_config = instance->config;
126
+ int max_async_calls = new_config.resident_async_pools + new_config.max_temporaries;
132
127
 
133
128
  Napi::Object obj = info[0].As<Napi::Object>();
134
129
  Napi::Array keys = obj.GetPropertyNames();
@@ -138,25 +133,25 @@ static Napi::Value GetSetConfig(const Napi::CallbackInfo &info)
138
133
  Napi::Value value = obj[key];
139
134
 
140
135
  if (key == "sync_stack_size") {
141
- if (!ChangeMemorySize(key.c_str(), value, &sync_stack_size))
136
+ if (!ChangeMemorySize(key.c_str(), value, &new_config.sync_stack_size))
142
137
  return env.Null();
143
138
  } else if (key == "sync_heap_size") {
144
- if (!ChangeMemorySize(key.c_str(), value, &sync_heap_size))
139
+ if (!ChangeMemorySize(key.c_str(), value, &new_config.sync_heap_size))
145
140
  return env.Null();
146
141
  } else if (key == "async_stack_size") {
147
- if (!ChangeMemorySize(key.c_str(), value, &async_stack_size))
142
+ if (!ChangeMemorySize(key.c_str(), value, &new_config.async_stack_size))
148
143
  return env.Null();
149
144
  } else if (key == "async_heap_size") {
150
- if (!ChangeMemorySize(key.c_str(), value, &async_heap_size))
145
+ if (!ChangeMemorySize(key.c_str(), value, &new_config.async_heap_size))
151
146
  return env.Null();
152
147
  } else if (key == "resident_async_pools") {
153
- if (!ChangeAsyncLimit(key.c_str(), value, RG_LEN(instance->memories.data) - 1, &resident_async_pools))
148
+ if (!ChangeAsyncLimit(key.c_str(), value, RG_LEN(instance->memories.data) - 1, &new_config.resident_async_pools))
154
149
  return env.Null();
155
150
  } else if (key == "max_async_calls") {
156
151
  if (!ChangeAsyncLimit(key.c_str(), value, MaxAsyncCalls, &max_async_calls))
157
152
  return env.Null();
158
153
  } else if (key == "max_type_size") {
159
- if (!ChangeSize(key.c_str(), value, 32, Mebibytes(512), &max_type_size))
154
+ if (!ChangeSize(key.c_str(), value, 32, Mebibytes(512), &new_config.max_type_size))
160
155
  return env.Null();
161
156
  } else {
162
157
  ThrowError<Napi::Error>(env, "Unexpected config member '%1'", key.c_str());
@@ -164,29 +159,36 @@ static Napi::Value GetSetConfig(const Napi::CallbackInfo &info)
164
159
  }
165
160
  }
166
161
 
167
- if (max_async_calls < resident_async_pools) {
162
+ if (max_async_calls < new_config.resident_async_pools) {
168
163
  ThrowError<Napi::Error>(env, "Setting max_async_calls must be >= to resident_async_pools");
169
164
  return env.Null();
170
165
  }
171
166
 
172
- instance->sync_stack_size = sync_stack_size;
173
- instance->sync_heap_size = sync_heap_size;
174
- instance->async_stack_size = async_stack_size;
175
- instance->async_heap_size = async_heap_size;
176
- instance->resident_async_pools = resident_async_pools;
177
- instance->max_temporaries = max_async_calls - resident_async_pools;
178
- instance->max_type_size = max_type_size;
167
+ new_config.max_temporaries = max_async_calls - new_config.resident_async_pools;
168
+ instance->config = new_config;
179
169
  }
180
170
 
181
171
  Napi::Object obj = Napi::Object::New(env);
182
172
 
183
- obj.Set("sync_stack_size", instance->sync_stack_size);
184
- obj.Set("sync_heap_size", instance->sync_heap_size);
185
- obj.Set("async_stack_size", instance->async_stack_size);
186
- obj.Set("async_heap_size", instance->async_heap_size);
187
- obj.Set("resident_async_pools", instance->resident_async_pools);
188
- obj.Set("max_async_calls", instance->resident_async_pools + instance->max_temporaries);
189
- obj.Set("max_type_size", instance->max_type_size);
173
+ obj.Set("sync_stack_size", instance->config.sync_stack_size);
174
+ obj.Set("sync_heap_size", instance->config.sync_heap_size);
175
+ obj.Set("async_stack_size", instance->config.async_stack_size);
176
+ obj.Set("async_heap_size", instance->config.async_heap_size);
177
+ obj.Set("resident_async_pools", instance->config.resident_async_pools);
178
+ obj.Set("max_async_calls", instance->config.resident_async_pools + instance->config.max_temporaries);
179
+ obj.Set("max_type_size", instance->config.max_type_size);
180
+
181
+ return obj;
182
+ }
183
+
184
+ static Napi::Value GetStats(const Napi::CallbackInfo &info)
185
+ {
186
+ Napi::Env env = info.Env();
187
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
188
+
189
+ Napi::Object obj = Napi::Object::New(env);
190
+
191
+ obj.Set("disposed", instance->stats.disposed);
190
192
 
191
193
  return obj;
192
194
  }
@@ -197,6 +199,14 @@ static inline bool CheckAlignment(int64_t align)
197
199
  return valid;
198
200
  }
199
201
 
202
+ static inline Napi::External<TypeInfo> WrapType(Napi::Env env, InstanceData *instance, const TypeInfo *type)
203
+ {
204
+ Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, (TypeInfo *)type);
205
+ SetValueTag(instance, external, &TypeInfoMarker);
206
+
207
+ return external;
208
+ }
209
+
200
210
  static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
201
211
  {
202
212
  Napi::Env env = info.Env();
@@ -277,7 +287,7 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
277
287
  size = member.offset + member.type->size;
278
288
  type->align = std::max(type->align, align);
279
289
 
280
- if (size > instance->max_type_size) {
290
+ if (size > instance->config.max_type_size) {
281
291
  ThrowError<Napi::Error>(env, "Struct '%1' size is too high (max = %2)", type->name, FmtMemSize(size));
282
292
  return env.Null();
283
293
  }
@@ -312,10 +322,7 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
312
322
  }
313
323
  err_guard.Disable();
314
324
 
315
- Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, type);
316
- SetValueTag(instance, external, &TypeInfoMarker);
317
-
318
- return external;
325
+ return WrapType(env, instance, type);
319
326
  }
320
327
 
321
328
  static Napi::Value CreatePaddedStructType(const Napi::CallbackInfo &info)
@@ -363,10 +370,7 @@ static Napi::Value CreateOpaqueType(const Napi::CallbackInfo &info)
363
370
  }
364
371
  err_guard.Disable();
365
372
 
366
- Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, type);
367
- SetValueTag(instance, external, &TypeInfoMarker);
368
-
369
- return external;
373
+ return WrapType(env, instance, type);
370
374
  }
371
375
 
372
376
  static Napi::Value CreatePointerType(const Napi::CallbackInfo &info)
@@ -436,10 +440,7 @@ static Napi::Value CreatePointerType(const Napi::CallbackInfo &info)
436
440
  type = copy;
437
441
  }
438
442
 
439
- Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, (TypeInfo *)type);
440
- SetValueTag(instance, external, &TypeInfoMarker);
441
-
442
- return external;
443
+ return WrapType(env, instance, type);
443
444
  }
444
445
 
445
446
  static Napi::Value EncodePointerDirection(const Napi::CallbackInfo &info, int directions)
@@ -463,13 +464,10 @@ static Napi::Value EncodePointerDirection(const Napi::CallbackInfo &info, int di
463
464
  return env.Null();
464
465
  }
465
466
 
466
- // We need to lose the const for Napi::External to work
467
- TypeInfo *marked = (TypeInfo *)((uint8_t *)type + directions - 1);
468
-
469
- Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, marked);
470
- SetValueTag(instance, external, &TypeInfoMarker);
467
+ // Embed direction in unused pointer bits
468
+ const TypeInfo *marked = (const TypeInfo *)((uint8_t *)type + directions - 1);
471
469
 
472
- return external;
470
+ return WrapType(env, instance, marked);
473
471
  }
474
472
 
475
473
  static Napi::Value MarkIn(const Napi::CallbackInfo &info)
@@ -543,10 +541,16 @@ static Napi::Value CreateDisposableType(const Napi::CallbackInfo &info)
543
541
  };
544
542
 
545
543
  ref.Call(self, RG_LEN(args), args);
544
+ instance->stats.disposed++;
546
545
  };
547
546
  dispose_func = func;
548
547
  } else {
549
- dispose = [](Napi::Env, const TypeInfo *, const void *ptr) { free((void *)ptr); };
548
+ dispose = [](Napi::Env env, const TypeInfo *, const void *ptr) {
549
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
550
+
551
+ free((void *)ptr);
552
+ instance->stats.disposed++;
553
+ };
550
554
  }
551
555
 
552
556
  TypeInfo *type = instance->types.AppendDefault();
@@ -570,10 +574,7 @@ static Napi::Value CreateDisposableType(const Napi::CallbackInfo &info)
570
574
  }
571
575
  err_guard.Disable();
572
576
 
573
- Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, type);
574
- SetValueTag(instance, external, &TypeInfoMarker);
575
-
576
- return external;
577
+ return WrapType(env, instance, type);
577
578
  }
578
579
 
579
580
  static Napi::Value CallFree(const Napi::CallbackInfo &info)
@@ -582,7 +583,7 @@ static Napi::Value CallFree(const Napi::CallbackInfo &info)
582
583
  InstanceData *instance = env.GetInstanceData<InstanceData>();
583
584
 
584
585
  if (info.Length() < 1) {
585
- ThrowError<Napi::TypeError>(env, "Expected 1 or 2 arguments, got %1", info.Length());
586
+ ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
586
587
  return env.Null();
587
588
  }
588
589
  if (!info[0].IsExternal() || CheckValueTag(instance, info[0], &TypeInfoMarker)) {
@@ -621,8 +622,8 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
621
622
  ThrowError<Napi::TypeError>(env, "Array length must be positive and non-zero");
622
623
  return env.Null();
623
624
  }
624
- if (len > instance->max_type_size / ref->size) {
625
- ThrowError<Napi::TypeError>(env, "Array length is too high (max = %1)", instance->max_type_size / ref->size);
625
+ if (len > instance->config.max_type_size / ref->size) {
626
+ ThrowError<Napi::TypeError>(env, "Array length is too high (max = %1)", instance->config.max_type_size / ref->size);
626
627
  return env.Null();
627
628
  }
628
629
 
@@ -658,10 +659,7 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
658
659
  type = MakeArrayType(instance, ref, len);
659
660
  }
660
661
 
661
- Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, (TypeInfo *)type);
662
- SetValueTag(instance, external, &TypeInfoMarker);
663
-
664
- return external;
662
+ return WrapType(env, instance, type);
665
663
  }
666
664
 
667
665
  static bool ParseClassicFunction(Napi::Env env, Napi::String name, Napi::Value ret,
@@ -786,10 +784,7 @@ static Napi::Value CreateCallbackType(const Napi::CallbackInfo &info)
786
784
 
787
785
  instance->types_map.Set(type->name, type);
788
786
 
789
- Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, type);
790
- SetValueTag(instance, external, &TypeInfoMarker);
791
-
792
- return external;
787
+ return WrapType(env, instance, type);
793
788
  }
794
789
 
795
790
  static Napi::Value CreateTypeAlias(const Napi::CallbackInfo &info)
@@ -821,10 +816,7 @@ static Napi::Value CreateTypeAlias(const Napi::CallbackInfo &info)
821
816
  return env.Null();
822
817
  }
823
818
 
824
- Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, (TypeInfo *)type);
825
- SetValueTag(instance, external, &TypeInfoMarker);
826
-
827
- return external;
819
+ return WrapType(env, instance, type);
828
820
  }
829
821
 
830
822
  static Napi::Value GetTypeSize(const Napi::CallbackInfo &info)
@@ -907,10 +899,7 @@ static Napi::Value GetResolvedType(const Napi::CallbackInfo &info)
907
899
  if (!type)
908
900
  return env.Null();
909
901
 
910
- Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, (TypeInfo *)type);
911
- SetValueTag(instance, external, &TypeInfoMarker);
912
-
913
- return external;
902
+ return WrapType(env, instance, type);
914
903
  }
915
904
 
916
905
  static Napi::Value GetTypeDefinition(const Napi::CallbackInfo &info)
@@ -934,6 +923,7 @@ static Napi::Value GetTypeDefinition(const Napi::CallbackInfo &info)
934
923
  defn.Set("primitive", PrimitiveKindNames[(int)type->primitive]);
935
924
  defn.Set("size", Napi::Number::New(env, (double)type->size));
936
925
  defn.Set("alignment", Napi::Number::New(env, (double)type->align));
926
+ defn.Set("disposable", Napi::Boolean::New(env, !!type->dispose));
937
927
 
938
928
  switch (type->primitive) {
939
929
  case PrimitiveKind::Void:
@@ -964,10 +954,8 @@ static Napi::Value GetTypeDefinition(const Napi::CallbackInfo &info)
964
954
  defn.Set("length", Napi::Number::New(env, (double)len));
965
955
  } [[fallthrough]];
966
956
  case PrimitiveKind::Pointer: {
967
- Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, (TypeInfo *)type->ref.type);
968
- SetValueTag(instance, external, &TypeInfoMarker);
969
-
970
- defn.Set("ref", external);
957
+ Napi::Value value = WrapType(env, instance, type->ref.type);
958
+ defn.Set("ref", value);
971
959
  } break;
972
960
  case PrimitiveKind::Record: {
973
961
  Napi::Object members = Napi::Object::New(env);
@@ -975,11 +963,8 @@ static Napi::Value GetTypeDefinition(const Napi::CallbackInfo &info)
975
963
  for (const RecordMember &member: type->members) {
976
964
  Napi::Object obj = Napi::Object::New(env);
977
965
 
978
- Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, (TypeInfo *)member.type);
979
- SetValueTag(instance, external, &TypeInfoMarker);
980
-
981
966
  obj.Set("name", member.name);
982
- obj.Set("type", external);
967
+ obj.Set("type", WrapType(env, instance, member.type));
983
968
  obj.Set("offset", member.offset);
984
969
 
985
970
  members.Set(member.name, obj);
@@ -1007,7 +992,7 @@ static InstanceMemory *AllocateMemory(InstanceData *instance, Size stack_size, S
1007
992
  return mem;
1008
993
  }
1009
994
 
1010
- if (RG_UNLIKELY(instance->temporaries >= instance->max_temporaries))
995
+ if (RG_UNLIKELY(instance->temporaries >= instance->config.max_temporaries))
1011
996
  return nullptr;
1012
997
 
1013
998
  InstanceMemory *mem = new InstanceMemory();
@@ -1065,7 +1050,7 @@ static InstanceMemory *AllocateMemory(InstanceData *instance, Size stack_size, S
1065
1050
 
1066
1051
  mem->depth = 0;
1067
1052
 
1068
- if (instance->memories.len <= instance->resident_async_pools) {
1053
+ if (instance->memories.len <= instance->config.resident_async_pools) {
1069
1054
  instance->memories.Append(mem);
1070
1055
  mem->temporary = false;
1071
1056
  } else {
@@ -1256,7 +1241,7 @@ static Napi::Value TranslateAsyncCall(const Napi::CallbackInfo &info)
1256
1241
  return env.Null();
1257
1242
  }
1258
1243
 
1259
- InstanceMemory *mem = AllocateMemory(instance, instance->async_stack_size, instance->async_heap_size);
1244
+ InstanceMemory *mem = AllocateMemory(instance, instance->config.async_stack_size, instance->config.async_heap_size);
1260
1245
  if (RG_UNLIKELY(!mem)) {
1261
1246
  ThrowError<Napi::Error>(env, "Too many asynchronous calls are running");
1262
1247
  return env.Null();
@@ -1350,6 +1335,23 @@ static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info, CallConve
1350
1335
  wrapper.Set("async", async);
1351
1336
  }
1352
1337
 
1338
+ // Create info object
1339
+ {
1340
+ Napi::Object meta = Napi::Object::New(env);
1341
+ Napi::Array arguments = Napi::Array::New(env, func->parameters.len);
1342
+
1343
+ meta.Set("name", Napi::String::New(env, func->name));
1344
+ meta.Set("arguments", arguments);
1345
+ meta.Set("result", WrapType(env, instance, func->ret.type));
1346
+
1347
+ for (Size i = 0; i < func->parameters.len; i++) {
1348
+ const ParameterInfo &param = func->parameters[i];
1349
+ arguments.Set((uint32_t)i, WrapType(env, instance, param.type));
1350
+ }
1351
+
1352
+ wrapper.Set("info", meta);
1353
+ }
1354
+
1353
1355
  return wrapper;
1354
1356
  }
1355
1357
 
@@ -1368,7 +1370,7 @@ static Napi::Value LoadSharedLibrary(const Napi::CallbackInfo &info)
1368
1370
  }
1369
1371
 
1370
1372
  if (!instance->memories.len) {
1371
- AllocateMemory(instance, instance->sync_stack_size, instance->sync_heap_size);
1373
+ AllocateMemory(instance, instance->config.sync_stack_size, instance->config.sync_heap_size);
1372
1374
  RG_ASSERT(instance->memories.len);
1373
1375
  }
1374
1376
 
@@ -1591,8 +1593,7 @@ static void RegisterPrimitiveType(Napi::Env env, Napi::Object map, std::initiali
1591
1593
  type->ref.marker = marker;
1592
1594
  }
1593
1595
 
1594
- Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, type);
1595
- SetValueTag(instance, external, &TypeInfoMarker);
1596
+ Napi::Value wrapper = WrapType(env, instance, type);
1596
1597
 
1597
1598
  for (const char *name: names) {
1598
1599
  bool inserted;
@@ -1600,7 +1601,7 @@ static void RegisterPrimitiveType(Napi::Env env, Napi::Object map, std::initiali
1600
1601
  RG_ASSERT(inserted);
1601
1602
 
1602
1603
  if (!EndsWith(name, "*")) {
1603
- map.Set(name, external);
1604
+ map.Set(name, wrapper);
1604
1605
  }
1605
1606
  }
1606
1607
  }
@@ -1974,7 +1975,7 @@ extern "C" void RelayCallback(Size idx, uint8_t *own_sp, uint8_t *caller_sp, Bac
1974
1975
  Napi::Env env = trampoline->func.Env();
1975
1976
  InstanceData *instance = env.GetInstanceData<InstanceData>();
1976
1977
 
1977
- InstanceMemory *mem = AllocateMemory(instance, instance->async_stack_size, instance->async_heap_size);
1978
+ InstanceMemory *mem = AllocateMemory(instance, instance->config.async_stack_size, instance->config.async_heap_size);
1978
1979
  if (RG_UNLIKELY(!mem)) {
1979
1980
  ThrowError<Napi::Error>(env, "Too many asynchronous calls are running");
1980
1981
  return;
@@ -1993,6 +1994,7 @@ template <typename Func>
1993
1994
  static void SetExports(Napi::Env env, Func func)
1994
1995
  {
1995
1996
  func("config", Napi::Function::New(env, GetSetConfig));
1997
+ func("stats", Napi::Function::New(env, GetStats));
1996
1998
 
1997
1999
  func("struct", Napi::Function::New(env, CreatePaddedStructType));
1998
2000
  func("pack", Napi::Function::New(env, CreatePackedStructType));
@@ -264,13 +264,19 @@ struct InstanceData {
264
264
 
265
265
  BlockAllocator str_alloc;
266
266
 
267
- Size sync_stack_size = DefaultSyncStackSize;
268
- Size sync_heap_size = DefaultSyncHeapSize;
269
- Size async_stack_size = DefaultAsyncStackSize;
270
- Size async_heap_size = DefaultAsyncHeapSize;
271
- int resident_async_pools = DefaultResidentAsyncPools;
272
- int max_temporaries = DefaultMaxAsyncCalls - DefaultResidentAsyncPools;
273
- Size max_type_size = DefaultMaxTypeSize;
267
+ struct {
268
+ Size sync_stack_size = DefaultSyncStackSize;
269
+ Size sync_heap_size = DefaultSyncHeapSize;
270
+ Size async_stack_size = DefaultAsyncStackSize;
271
+ Size async_heap_size = DefaultAsyncHeapSize;
272
+ int resident_async_pools = DefaultResidentAsyncPools;
273
+ int max_temporaries = DefaultMaxAsyncCalls - DefaultResidentAsyncPools;
274
+ Size max_type_size = DefaultMaxTypeSize;
275
+ } config;
276
+
277
+ struct {
278
+ int64_t disposed = 0;
279
+ } stats;
274
280
  };
275
281
  RG_STATIC_ASSERT(DefaultResidentAsyncPools <= RG_LEN(InstanceData::memories.data) - 1);
276
282
  RG_STATIC_ASSERT(DefaultMaxAsyncCalls >= DefaultResidentAsyncPools);
@@ -25,11 +25,19 @@ declare module 'koffi' {
25
25
  primitive: string;
26
26
  size: number;
27
27
  alignment: number;
28
+ disposable: boolean;
28
29
  length: number;
29
30
  ref: IKoffiCType;
30
31
  members: Record<string, { name: string, type: IKoffiCType, offset: number }>;
31
32
  };
32
- type KoffiFunction = Function & { async: Function };
33
+ type KoffiFunction = Function & {
34
+ async: Function;
35
+ info: {
36
+ name: string,
37
+ arguments: IKoffiCType[],
38
+ result: IKoffiCType
39
+ };
40
+ };
33
41
 
34
42
  export interface IKoffiLib {
35
43
  func(definition: string): KoffiFunction;
@@ -92,4 +100,5 @@ declare module 'koffi' {
92
100
 
93
101
  export function config(): Record<string, unknown>;
94
102
  export function config(cfg: Record<string, unknown>): Record<string, unknown>;
103
+ export function stats(): Record<string, unknown>;
95
104
  }
@@ -141,34 +141,36 @@ const TypeInfo *PrototypeParser::ParseType()
141
141
 
142
142
  if (offset >= tokens.len) {
143
143
  MarkError("Unexpected end of prototype, expected type");
144
- return instance->types_map.FindValue("void", nullptr);
144
+ return instance->void_type;
145
145
  } else if (!IsIdentifier(tokens[offset])) {
146
146
  MarkError("Unexpected token '%1', expected type", tokens[offset]);
147
- return instance->types_map.FindValue("void", nullptr);
147
+ return instance->void_type;
148
148
  }
149
149
 
150
- while (offset < tokens.len && (IsIdentifier(tokens[offset]) ||
151
- tokens[offset] == '*')) {
152
- offset++;
153
- }
154
- offset += (offset < tokens.len && tokens[offset] == "!");
155
- offset = std::min(tokens.len - 1, offset);
150
+ while (++offset < tokens.len && IsIdentifier(tokens[offset]));
151
+ offset--;
152
+ while (++offset < tokens.len && (tokens[offset] == '*' ||
153
+ tokens[offset] == '!' ||
154
+ tokens[offset] == "const"));
155
+ offset--;
156
156
 
157
157
  while (offset >= start) {
158
158
  Span<const char> str = MakeSpan(tokens[start].ptr, tokens[offset].end() - tokens[start].ptr);
159
- const TypeInfo *type = ResolveType(instance, str);
159
+ const TypeInfo *type = ResolveType(env, str);
160
160
 
161
161
  if (type) {
162
162
  offset++;
163
163
  return type;
164
164
  }
165
+ if (RG_UNLIKELY(env.IsExceptionPending()))
166
+ return instance->void_type;
165
167
 
166
168
  offset--;
167
169
  }
168
170
  offset = start;
169
171
 
170
172
  MarkError("Unknown or invalid type name '%1'", tokens[offset]);
171
- return instance->types_map.FindValue("void", nullptr);
173
+ return instance->void_type;
172
174
  }
173
175
 
174
176
  const char *PrototypeParser::ParseIdentifier()