koffi 2.3.4 → 2.3.6-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. package/CHANGELOG.md +25 -2
  2. package/doc/changelog.md +4 -0
  3. package/doc/index.rst +1 -2
  4. package/doc/types.md +3 -3
  5. package/package.json +5 -5
  6. package/src/cnoke/cnoke.js +40 -834
  7. package/src/cnoke/package.json +1 -0
  8. package/src/cnoke/src/builder.js +447 -0
  9. package/src/cnoke/src/index.js +20 -0
  10. package/src/cnoke/src/tools.js +401 -0
  11. package/src/core/libcc/libcc.cc +2 -2
  12. package/src/koffi/build/2.3.6-beta.1/koffi_darwin_arm64/koffi.node +0 -0
  13. package/src/koffi/build/2.3.6-beta.1/koffi_darwin_x64/koffi.node +0 -0
  14. package/src/koffi/build/2.3.6-beta.1/koffi_freebsd_arm64/koffi.node +0 -0
  15. package/src/koffi/build/2.3.6-beta.1/koffi_freebsd_ia32/koffi.node +0 -0
  16. package/src/koffi/build/2.3.6-beta.1/koffi_freebsd_x64/koffi.node +0 -0
  17. package/src/koffi/build/2.3.6-beta.1/koffi_linux_arm32hf/koffi.node +0 -0
  18. package/src/koffi/build/2.3.6-beta.1/koffi_linux_arm64/koffi.node +0 -0
  19. package/src/koffi/build/2.3.6-beta.1/koffi_linux_ia32/koffi.node +0 -0
  20. package/src/koffi/build/2.3.6-beta.1/koffi_linux_riscv64hf64/koffi.node +0 -0
  21. package/src/koffi/build/2.3.6-beta.1/koffi_linux_x64/koffi.node +0 -0
  22. package/src/koffi/build/2.3.6-beta.1/koffi_openbsd_ia32/koffi.node +0 -0
  23. package/src/koffi/build/2.3.6-beta.1/koffi_openbsd_x64/koffi.node +0 -0
  24. package/src/koffi/build/2.3.6-beta.1/koffi_win32_arm64/koffi.exp +0 -0
  25. package/src/koffi/build/2.3.6-beta.1/koffi_win32_arm64/koffi.lib +0 -0
  26. package/src/koffi/build/2.3.6-beta.1/koffi_win32_arm64/koffi.node +0 -0
  27. package/src/koffi/build/2.3.6-beta.1/koffi_win32_arm64/koffi.pdb +0 -0
  28. package/src/koffi/build/2.3.6-beta.1/koffi_win32_ia32/koffi.exp +0 -0
  29. package/src/koffi/build/2.3.6-beta.1/koffi_win32_ia32/koffi.lib +0 -0
  30. package/src/koffi/build/2.3.6-beta.1/koffi_win32_ia32/koffi.node +0 -0
  31. package/src/koffi/build/2.3.6-beta.1/koffi_win32_ia32/koffi.pdb +0 -0
  32. package/src/koffi/build/2.3.6-beta.1/koffi_win32_x64/koffi.exp +0 -0
  33. package/src/koffi/build/2.3.6-beta.1/koffi_win32_x64/koffi.lib +0 -0
  34. package/src/koffi/build/2.3.6-beta.1/koffi_win32_x64/koffi.node +0 -0
  35. package/src/koffi/build/2.3.6-beta.1/koffi_win32_x64/koffi.pdb +0 -0
  36. package/src/koffi/src/abi_arm32.cc +43 -14
  37. package/src/koffi/src/abi_arm64.cc +95 -21
  38. package/src/koffi/src/abi_riscv64.cc +125 -64
  39. package/src/koffi/src/abi_x64_sysv.cc +38 -20
  40. package/src/koffi/src/abi_x64_win.cc +11 -5
  41. package/src/koffi/src/abi_x86.cc +14 -7
  42. package/src/koffi/src/call.cc +114 -44
  43. package/src/koffi/src/call.hh +6 -4
  44. package/src/koffi/src/ffi.cc +172 -147
  45. package/src/koffi/src/ffi.hh +18 -10
  46. package/src/koffi/src/index.d.ts +28 -7
  47. package/src/koffi/src/index.js +23 -4
  48. package/src/koffi/src/util.cc +261 -69
  49. package/src/koffi/src/util.hh +34 -8
  50. package/vendor/node-addon-api/CHANGELOG.md +122 -9
  51. package/vendor/node-addon-api/CONTRIBUTING.md +10 -10
  52. package/vendor/node-addon-api/README.md +36 -12
  53. package/vendor/node-addon-api/benchmark/function_args.cc +95 -62
  54. package/vendor/node-addon-api/benchmark/function_args.js +6 -6
  55. package/vendor/node-addon-api/benchmark/index.js +1 -1
  56. package/vendor/node-addon-api/benchmark/property_descriptor.cc +27 -34
  57. package/vendor/node-addon-api/benchmark/property_descriptor.js +5 -4
  58. package/vendor/node-addon-api/doc/async_operations.md +1 -1
  59. package/vendor/node-addon-api/doc/async_worker_variants.md +23 -2
  60. package/vendor/node-addon-api/doc/cmake-js.md +1 -1
  61. package/vendor/node-addon-api/doc/error_handling.md +3 -3
  62. package/vendor/node-addon-api/doc/external.md +7 -0
  63. package/vendor/node-addon-api/doc/handle_scope.md +14 -0
  64. package/vendor/node-addon-api/doc/hierarchy.md +1 -1
  65. package/vendor/node-addon-api/doc/object.md +27 -0
  66. package/vendor/node-addon-api/index.js +3 -3
  67. package/vendor/node-addon-api/napi-inl.deprecated.h +121 -127
  68. package/vendor/node-addon-api/napi-inl.h +1178 -1144
  69. package/vendor/node-addon-api/napi.h +2786 -2675
  70. package/vendor/node-addon-api/package.json +42 -1
  71. package/vendor/node-addon-api/test/addon.cc +8 -6
  72. package/vendor/node-addon-api/test/addon_build/index.js +9 -9
  73. package/vendor/node-addon-api/test/addon_build/tpl/addon.cc +2 -1
  74. package/vendor/node-addon-api/test/addon_build/tpl/index.js +4 -4
  75. package/vendor/node-addon-api/test/addon_data.cc +12 -13
  76. package/vendor/node-addon-api/test/array_buffer.js +3 -2
  77. package/vendor/node-addon-api/test/async_progress_queue_worker.cc +13 -3
  78. package/vendor/node-addon-api/test/async_progress_queue_worker.js +5 -5
  79. package/vendor/node-addon-api/test/async_progress_worker.cc +65 -9
  80. package/vendor/node-addon-api/test/async_progress_worker.js +14 -9
  81. package/vendor/node-addon-api/test/async_worker.cc +236 -3
  82. package/vendor/node-addon-api/test/async_worker.js +122 -37
  83. package/vendor/node-addon-api/test/async_worker_nocallback.js +9 -3
  84. package/vendor/node-addon-api/test/async_worker_persistent.js +2 -2
  85. package/vendor/node-addon-api/test/basic_types/array.js +3 -4
  86. package/vendor/node-addon-api/test/basic_types/boolean.cc +4 -2
  87. package/vendor/node-addon-api/test/basic_types/boolean.js +1 -2
  88. package/vendor/node-addon-api/test/basic_types/number.cc +12 -6
  89. package/vendor/node-addon-api/test/basic_types/number.js +19 -18
  90. package/vendor/node-addon-api/test/basic_types/value.cc +52 -1
  91. package/vendor/node-addon-api/test/basic_types/value.js +44 -21
  92. package/vendor/node-addon-api/test/bigint.cc +2 -1
  93. package/vendor/node-addon-api/test/binding.cc +11 -5
  94. package/vendor/node-addon-api/test/binding.gyp +3 -1
  95. package/vendor/node-addon-api/test/buffer.cc +46 -38
  96. package/vendor/node-addon-api/test/buffer.js +12 -12
  97. package/vendor/node-addon-api/test/callbackInfo.cc +27 -0
  98. package/vendor/node-addon-api/test/callbackInfo.js +9 -0
  99. package/vendor/node-addon-api/test/callbackscope.cc +19 -2
  100. package/vendor/node-addon-api/test/callbackscope.js +20 -20
  101. package/vendor/node-addon-api/test/common/index.js +37 -4
  102. package/vendor/node-addon-api/test/dataview/dataview.js +5 -5
  103. package/vendor/node-addon-api/test/dataview/dataview_read_write.js +14 -12
  104. package/vendor/node-addon-api/test/date.cc +2 -1
  105. package/vendor/node-addon-api/test/date.js +2 -2
  106. package/vendor/node-addon-api/test/env_cleanup.cc +12 -0
  107. package/vendor/node-addon-api/test/env_cleanup.js +38 -39
  108. package/vendor/node-addon-api/test/error.cc +6 -5
  109. package/vendor/node-addon-api/test/error_terminating_environment.js +64 -60
  110. package/vendor/node-addon-api/test/external.cc +36 -32
  111. package/vendor/node-addon-api/test/external.js +43 -46
  112. package/vendor/node-addon-api/test/function.cc +58 -44
  113. package/vendor/node-addon-api/test/function.js +4 -0
  114. package/vendor/node-addon-api/test/function_reference.cc +15 -13
  115. package/vendor/node-addon-api/test/globalObject/global_object_delete_property.js +50 -53
  116. package/vendor/node-addon-api/test/globalObject/global_object_get_property.js +33 -34
  117. package/vendor/node-addon-api/test/globalObject/global_object_has_own_property.js +38 -40
  118. package/vendor/node-addon-api/test/globalObject/global_object_set_property.js +47 -49
  119. package/vendor/node-addon-api/test/handlescope.cc +29 -3
  120. package/vendor/node-addon-api/test/handlescope.js +5 -3
  121. package/vendor/node-addon-api/test/index.js +1 -5
  122. package/vendor/node-addon-api/test/maybe/check.cc +49 -3
  123. package/vendor/node-addon-api/test/maybe/index.js +19 -7
  124. package/vendor/node-addon-api/test/memory_management.cc +9 -8
  125. package/vendor/node-addon-api/test/memory_management.js +2 -2
  126. package/vendor/node-addon-api/test/movable_callbacks.js +2 -2
  127. package/vendor/node-addon-api/test/name.js +3 -3
  128. package/vendor/node-addon-api/test/napi_child.js +2 -2
  129. package/vendor/node-addon-api/test/object/delete_property.js +7 -7
  130. package/vendor/node-addon-api/test/object/finalizer.cc +13 -12
  131. package/vendor/node-addon-api/test/object/finalizer.js +2 -2
  132. package/vendor/node-addon-api/test/object/get_property.js +6 -6
  133. package/vendor/node-addon-api/test/object/has_own_property.js +3 -3
  134. package/vendor/node-addon-api/test/object/has_property.js +4 -4
  135. package/vendor/node-addon-api/test/object/object.cc +191 -111
  136. package/vendor/node-addon-api/test/object/object.js +53 -52
  137. package/vendor/node-addon-api/test/object/object_deprecated.cc +24 -20
  138. package/vendor/node-addon-api/test/object/object_deprecated.js +3 -8
  139. package/vendor/node-addon-api/test/object/object_freeze_seal.js +54 -54
  140. package/vendor/node-addon-api/test/object/object_type_tag.cc +39 -0
  141. package/vendor/node-addon-api/test/object/object_type_tag.js +55 -0
  142. package/vendor/node-addon-api/test/object/subscript_operator.js +2 -2
  143. package/vendor/node-addon-api/test/object_reference.js +100 -100
  144. package/vendor/node-addon-api/test/objectwrap.cc +41 -34
  145. package/vendor/node-addon-api/test/objectwrap.js +23 -19
  146. package/vendor/node-addon-api/test/objectwrap_constructor_exception.cc +5 -5
  147. package/vendor/node-addon-api/test/objectwrap_constructor_exception.js +1 -1
  148. package/vendor/node-addon-api/test/objectwrap_multiple_inheritance.cc +7 -7
  149. package/vendor/node-addon-api/test/objectwrap_multiple_inheritance.js +1 -1
  150. package/vendor/node-addon-api/test/objectwrap_removewrap.js +24 -32
  151. package/vendor/node-addon-api/test/objectwrap_worker_thread.js +5 -4
  152. package/vendor/node-addon-api/test/promise.cc +7 -0
  153. package/vendor/node-addon-api/test/promise.js +3 -1
  154. package/vendor/node-addon-api/test/reference.cc +1 -1
  155. package/vendor/node-addon-api/test/reference.js +2 -2
  156. package/vendor/node-addon-api/test/run_script.cc +1 -1
  157. package/vendor/node-addon-api/test/symbol.js +59 -66
  158. package/vendor/node-addon-api/test/testUtil.js +6 -6
  159. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function.cc +64 -29
  160. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function.js +71 -34
  161. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_ctx.cc +111 -19
  162. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_ctx.js +2 -1
  163. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_existing_tsfn.cc +36 -26
  164. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_existing_tsfn.js +5 -5
  165. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_ptr.cc +3 -2
  166. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_ptr.js +1 -1
  167. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_sum.cc +47 -32
  168. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_sum.js +3 -3
  169. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_unref.cc +22 -9
  170. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_unref.js +76 -31
  171. package/vendor/node-addon-api/test/thunking_manual.cc +61 -74
  172. package/vendor/node-addon-api/test/thunking_manual.js +6 -7
  173. package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function.cc +20 -20
  174. package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function.js +19 -19
  175. package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_ctx.cc +57 -5
  176. package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_ctx.js +2 -0
  177. package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_existing_tsfn.js +5 -5
  178. package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_ptr.cc +5 -1
  179. package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_ptr.js +4 -3
  180. package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_sum.js +3 -3
  181. package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_unref.cc +14 -0
  182. package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_unref.js +76 -31
  183. package/vendor/node-addon-api/test/typedarray-bigint.js +2 -2
  184. package/vendor/node-addon-api/test/typedarray.cc +263 -70
  185. package/vendor/node-addon-api/test/typedarray.js +44 -10
  186. package/vendor/node-addon-api/test/version_management.cc +16 -15
  187. package/vendor/node-addon-api/test/version_management.js +18 -20
  188. package/vendor/node-addon-api/tools/check-napi.js +13 -14
  189. package/vendor/node-addon-api/tools/conversion.js +161 -169
  190. package/vendor/node-addon-api/tools/eslint-format.js +9 -1
  191. package/vendor/node-addon-api/unit-test/README.md +4 -4
  192. package/src/koffi/build/2.3.4/koffi_darwin_arm64.tar.gz +0 -0
  193. package/src/koffi/build/2.3.4/koffi_darwin_x64.tar.gz +0 -0
  194. package/src/koffi/build/2.3.4/koffi_freebsd_arm64.tar.gz +0 -0
  195. package/src/koffi/build/2.3.4/koffi_freebsd_ia32.tar.gz +0 -0
  196. package/src/koffi/build/2.3.4/koffi_freebsd_x64.tar.gz +0 -0
  197. package/src/koffi/build/2.3.4/koffi_linux_arm32hf.tar.gz +0 -0
  198. package/src/koffi/build/2.3.4/koffi_linux_arm64.tar.gz +0 -0
  199. package/src/koffi/build/2.3.4/koffi_linux_ia32.tar.gz +0 -0
  200. package/src/koffi/build/2.3.4/koffi_linux_riscv64hf64.tar.gz +0 -0
  201. package/src/koffi/build/2.3.4/koffi_linux_x64.tar.gz +0 -0
  202. package/src/koffi/build/2.3.4/koffi_openbsd_ia32.tar.gz +0 -0
  203. package/src/koffi/build/2.3.4/koffi_openbsd_x64.tar.gz +0 -0
  204. package/src/koffi/build/2.3.4/koffi_win32_arm64.tar.gz +0 -0
  205. package/src/koffi/build/2.3.4/koffi_win32_ia32.tar.gz +0 -0
  206. package/src/koffi/build/2.3.4/koffi_win32_x64.tar.gz +0 -0
@@ -48,10 +48,6 @@ namespace RG {
48
48
 
49
49
  SharedData shared;
50
50
 
51
- // Value does not matter, the tag system uses memory addresses
52
- const int TypeInfoMarker = 0xDEADBEEF;
53
- const int CastMarker = 0xDEADBEEF;
54
-
55
51
  static RG_THREAD_LOCAL CallData *exec_call;
56
52
 
57
53
  static bool ChangeSize(const char *name, Napi::Value value, Size min_size, Size max_size, Size *out_size)
@@ -335,6 +331,147 @@ static Napi::Value CreatePackedStructType(const Napi::CallbackInfo &info)
335
331
  return CreateStructType(info, false);
336
332
  }
337
333
 
334
+ static Napi::Value CreateUnionType(const Napi::CallbackInfo &info)
335
+ {
336
+ Napi::Env env = info.Env();
337
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
338
+
339
+ if (info.Length() < 1) {
340
+ ThrowError<Napi::TypeError>(env, "Expected 1 or 2 arguments, got %1", info.Length());
341
+ return env.Null();
342
+ }
343
+
344
+ bool named = info.Length() > 1;
345
+
346
+ if (named && !info[0].IsString()) {
347
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
348
+ return env.Null();
349
+ }
350
+ if (!IsObject(info[named])) {
351
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for members, expected object", GetValueType(instance, info[1]));
352
+ return env.Null();
353
+ }
354
+
355
+ TypeInfo *type = instance->types.AppendDefault();
356
+ RG_DEFER_N(err_guard) { instance->types.RemoveLast(1); };
357
+
358
+ std::string name = named ? info[0].As<Napi::String>() : std::string("<anonymous>");
359
+ Napi::Object obj = info[named].As<Napi::Object>();
360
+ Napi::Array keys = obj.GetPropertyNames();
361
+
362
+ type->name = DuplicateString(name.c_str(), &instance->str_alloc).ptr;
363
+
364
+ type->primitive = PrimitiveKind::Union;
365
+ type->align = 1;
366
+
367
+ HashSet<const char *> members;
368
+ int32_t size = 0;
369
+
370
+ for (uint32_t i = 0; i < keys.Length(); i++) {
371
+ RecordMember member = {};
372
+
373
+ std::string key = ((Napi::Value)keys[i]).As<Napi::String>();
374
+ Napi::Value value = obj[key];
375
+ int16_t align = 0;
376
+
377
+ member.name = DuplicateString(key.c_str(), &instance->str_alloc).ptr;
378
+
379
+ if (value.IsArray()) {
380
+ Napi::Array array = value.As<Napi::Array>();
381
+
382
+ if (array.Length() != 2 || !((Napi::Value)array[0u]).IsNumber()) {
383
+ ThrowError<Napi::Error>(env, "Member specifier array must contain alignement value and type");
384
+ return env.Null();
385
+ }
386
+
387
+ int64_t align64 = ((Napi::Value)array[0u]).As<Napi::Number>().Int64Value();
388
+
389
+ if (!CheckAlignment(align64)) {
390
+ ThrowError<Napi::Error>(env, "Alignment of member '%1' must be 1, 2, 4 or 8", member.name);
391
+ return env.Null();
392
+ }
393
+
394
+ value = array[1u];
395
+ align = (int16_t)align64;
396
+ }
397
+
398
+ member.type = ResolveType(value);
399
+ if (!member.type)
400
+ return env.Null();
401
+ if (!CanStoreType(member.type)) {
402
+ ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a member (maybe try %1 *)", member.type->name);
403
+ return env.Null();
404
+ }
405
+
406
+ align = align ? align : member.type->align;
407
+ size = std::max(size, member.type->size);
408
+ type->align = std::max(type->align, align);
409
+
410
+ bool inserted;
411
+ members.TrySet(member.name, &inserted);
412
+
413
+ if (!inserted) {
414
+ ThrowError<Napi::Error>(env, "Duplicate member '%1' in union '%2'", member.name, type->name);
415
+ return env.Null();
416
+ }
417
+
418
+ type->members.Append(member);
419
+ }
420
+
421
+ size = (int32_t)AlignLen(size, type->align);
422
+ if (!size) {
423
+ ThrowError<Napi::Error>(env, "Empty union '%1' is not allowed in C", type->name);
424
+ return env.Null();
425
+ }
426
+ type->size = (int32_t)size;
427
+
428
+ // If the insert succeeds, we cannot fail anymore
429
+ if (named) {
430
+ bool inserted;
431
+ instance->types_map.TrySet(type->name, type, &inserted);
432
+
433
+ if (!inserted) {
434
+ ThrowError<Napi::Error>(env, "Duplicate type name '%1'", type->name);
435
+ return env.Null();
436
+ }
437
+ }
438
+ err_guard.Disable();
439
+
440
+ // Union constructor
441
+ Napi::Function constructor = MagicUnion::InitClass(env, type);
442
+ type->construct.Reset(constructor, 1);
443
+
444
+ return WrapType(env, instance, type);
445
+ }
446
+
447
+ Napi::Value InstantiateUnion(const Napi::CallbackInfo &info)
448
+ {
449
+ Napi::Env env = info.Env();
450
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
451
+
452
+ if (!info.IsConstructCall()) {
453
+ ThrowError<Napi::TypeError>(env, "This function is a constructor and must be called with new");
454
+ return env.Null();
455
+ }
456
+ if (info.Length() < 1) {
457
+ ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
458
+ return env.Null();
459
+ }
460
+
461
+ const TypeInfo *type = ResolveType(info[0]);
462
+ if (!type)
463
+ return env.Null();
464
+ if (type->primitive != PrimitiveKind::Union) {
465
+ ThrowError<Napi::TypeError>(env, "Expected union type, got %1", PrimitiveKindNames[(int)type->primitive]);
466
+ return env.Null();
467
+ }
468
+
469
+ Napi::Object wrapper = type->construct.New({}).As<Napi::Object>();
470
+ SetValueTag(instance, wrapper, &MagicUnionMarker);
471
+
472
+ return wrapper;
473
+ }
474
+
338
475
  static Napi::Value CreateOpaqueType(const Napi::CallbackInfo &info)
339
476
  {
340
477
  Napi::Env env = info.Env();
@@ -636,21 +773,21 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
636
773
  }
637
774
 
638
775
  std::string to = info[2].As<Napi::String>();
639
- TypeInfo::ArrayHint hint = {};
776
+ ArrayHint hint = {};
640
777
 
641
- if (to == "typed") {
642
- hint = TypeInfo::ArrayHint::TypedArray;
643
- } else if (to == "array") {
644
- hint = TypeInfo::ArrayHint::Array;
645
- } else if (to == "string") {
778
+ if (to == "Typed" || to == "typed") {
779
+ hint = ArrayHint::Typed;
780
+ } else if (to == "Array" || to == "array") {
781
+ hint = ArrayHint::Array;
782
+ } else if (to == "String" || to == "string") {
646
783
  if (ref->primitive != PrimitiveKind::Int8 && ref->primitive != PrimitiveKind::Int16) {
647
- ThrowError<Napi::Error>(env, "Array hint 'string' can only be used with 8 and 16-bit signed integer types");
784
+ ThrowError<Napi::Error>(env, "Array hint 'String' can only be used with 8 and 16-bit signed integer types");
648
785
  return env.Null();
649
786
  }
650
787
 
651
- hint = TypeInfo::ArrayHint::String;
788
+ hint = ArrayHint::String;
652
789
  } else {
653
- ThrowError<Napi::Error>(env, "Array conversion hint must be 'typed', 'array' or 'string'");
790
+ ThrowError<Napi::Error>(env, "Array conversion hint must be 'Typed', 'Array' or 'String'");
654
791
  return env.Null();
655
792
  }
656
793
 
@@ -952,12 +1089,14 @@ static Napi::Value GetTypeDefinition(const Napi::CallbackInfo &info)
952
1089
  case PrimitiveKind::Array: {
953
1090
  uint32_t len = type->size / type->ref.type->size;
954
1091
  defn.Set("length", Napi::Number::New(env, (double)len));
1092
+ defn.Set("hint", ArrayHintNames[(int)type->hint]);
955
1093
  } [[fallthrough]];
956
1094
  case PrimitiveKind::Pointer: {
957
1095
  Napi::Value value = WrapType(env, instance, type->ref.type);
958
1096
  defn.Set("ref", value);
959
1097
  } break;
960
- case PrimitiveKind::Record: {
1098
+ case PrimitiveKind::Record:
1099
+ case PrimitiveKind::Union: {
961
1100
  Napi::Object members = Napi::Object::New(env);
962
1101
 
963
1102
  for (const RecordMember &member: type->members) {
@@ -988,11 +1127,15 @@ static InstanceMemory *AllocateMemory(InstanceData *instance, Size stack_size, S
988
1127
  for (Size i = 1; i < instance->memories.len; i++) {
989
1128
  InstanceMemory *mem = instance->memories[i];
990
1129
 
991
- if (!mem->depth)
1130
+ if (!mem->busy) {
1131
+ mem->busy = true;
992
1132
  return mem;
1133
+ }
993
1134
  }
994
1135
 
995
- if (RG_UNLIKELY(instance->temporaries >= instance->config.max_temporaries))
1136
+ bool temporary = (instance->memories.len > instance->config.resident_async_pools);
1137
+
1138
+ if (RG_UNLIKELY(temporary && instance->temporaries >= instance->config.max_temporaries))
996
1139
  return nullptr;
997
1140
 
998
1141
  InstanceMemory *mem = new InstanceMemory();
@@ -1048,16 +1191,16 @@ static InstanceMemory *AllocateMemory(InstanceData *instance, Size stack_size, S
1048
1191
  #endif
1049
1192
  RG_CRITICAL(mem->heap.ptr, "Failed to allocate %1 of memory", mem->heap.len);
1050
1193
 
1051
- mem->depth = 0;
1052
-
1053
- if (instance->memories.len <= instance->config.resident_async_pools) {
1054
- instance->memories.Append(mem);
1055
- mem->temporary = false;
1056
- } else {
1194
+ if (temporary) {
1057
1195
  instance->temporaries++;
1058
1196
  mem->temporary = true;
1197
+ } else {
1198
+ instance->memories.Append(mem);
1199
+ mem->temporary = false;
1059
1200
  }
1060
1201
 
1202
+ mem->busy = true;
1203
+
1061
1204
  mem_guard.Disable();
1062
1205
  return mem;
1063
1206
  }
@@ -1820,7 +1963,6 @@ static Napi::Value CastValue(const Napi::CallbackInfo &info)
1820
1963
  static Napi::Value DecodeValue(const Napi::CallbackInfo &info)
1821
1964
  {
1822
1965
  Napi::Env env = info.Env();
1823
- InstanceData *instance = env.GetInstanceData<InstanceData>();
1824
1966
 
1825
1967
  bool has_offset = (info.Length() >= 2 && info[1].IsNumber());
1826
1968
  bool has_len = (info.Length() >= 3u + has_offset && info[2u + has_offset].IsNumber());
@@ -1836,136 +1978,16 @@ static Napi::Value DecodeValue(const Napi::CallbackInfo &info)
1836
1978
 
1837
1979
  Napi::Value value = info[0];
1838
1980
  int64_t offset = has_offset ? info[1].As<Napi::Number>().Int64Value() : 0;
1839
-
1840
- const uint8_t *ptr = nullptr;
1841
-
1842
- if (value.IsExternal()) {
1843
- Napi::External<void> external = value.As<Napi::External<void>>();
1844
- ptr = (const uint8_t *)external.Data();
1845
- } else if (IsRawBuffer(value)) {
1846
- Span<uint8_t> buffer = GetRawBuffer(value);
1847
-
1848
- if (RG_UNLIKELY(buffer.len - offset < type->size)) {
1849
- ThrowError<Napi::Error>(env, "Expected buffer with size superior or equal to type %1 (%2 bytes)",
1850
- type->name, type->size + offset);
1851
- return env.Null();
1852
- }
1853
-
1854
- ptr = (const uint8_t *)buffer.ptr;
1855
- } else {
1856
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for variable, expected external or TypedArray", GetValueType(instance, info[0]));
1857
- return env.Null();
1858
- }
1859
-
1860
- if (!ptr)
1861
- return env.Null();
1862
- ptr += offset;
1863
-
1864
- // Used for strings and arrays, ignored otherwise
1865
1981
  int64_t len = has_len ? info[2u + has_offset].As<Napi::Number>().Int64Value() : -1;
1866
1982
 
1867
- if (has_len) {
1868
- if (RG_UNLIKELY(len < 0)) {
1869
- ThrowError<Napi::TypeError>(env, "Length must not be a negative value");
1870
- return env.Null();
1871
- }
1872
-
1873
- if (type->primitive != PrimitiveKind::String && type->primitive != PrimitiveKind::String16) {
1874
- type = MakeArrayType(instance, type, len);
1875
- }
1876
- }
1877
-
1878
- #define RETURN_INT(Type, NewCall) \
1879
- do { \
1880
- Type v = *(Type *)ptr; \
1881
- return NewCall(env, v); \
1882
- } while (false)
1883
- #define RETURN_INT_SWAP(Type, NewCall) \
1884
- do { \
1885
- Type v = ReverseBytes(*(Type *)ptr); \
1886
- return NewCall(env, v); \
1887
- } while (false)
1888
-
1889
- switch (type->primitive) {
1890
- case PrimitiveKind::Void: {
1891
- ThrowError<Napi::TypeError>(env, "Cannot decode value of type %1", type->name);
1892
- return env.Null();
1893
- } break;
1894
-
1895
- case PrimitiveKind::Bool: {
1896
- bool v = *(bool *)ptr;
1897
- return Napi::Boolean::New(env, v);
1898
- } break;
1899
- case PrimitiveKind::Int8: { RETURN_INT(int8_t, Napi::Number::New); } break;
1900
- case PrimitiveKind::UInt8: { RETURN_INT(uint8_t, Napi::Number::New); } break;
1901
- case PrimitiveKind::Int16: { RETURN_INT(int16_t, Napi::Number::New); } break;
1902
- case PrimitiveKind::Int16S: { RETURN_INT_SWAP(int16_t, Napi::Number::New); } break;
1903
- case PrimitiveKind::UInt16: { RETURN_INT(uint16_t, Napi::Number::New); } break;
1904
- case PrimitiveKind::UInt16S: { RETURN_INT_SWAP(uint16_t, Napi::Number::New); } break;
1905
- case PrimitiveKind::Int32: { RETURN_INT(int32_t, Napi::Number::New); } break;
1906
- case PrimitiveKind::Int32S: { RETURN_INT_SWAP(int32_t, Napi::Number::New); } break;
1907
- case PrimitiveKind::UInt32: { RETURN_INT(uint32_t, Napi::Number::New); } break;
1908
- case PrimitiveKind::UInt32S: { RETURN_INT_SWAP(uint32_t, Napi::Number::New); } break;
1909
- case PrimitiveKind::Int64: { RETURN_INT(int64_t, NewBigInt); } break;
1910
- case PrimitiveKind::Int64S: { RETURN_INT_SWAP(int64_t, NewBigInt); } break;
1911
- case PrimitiveKind::UInt64: { RETURN_INT(uint64_t, NewBigInt); } break;
1912
- case PrimitiveKind::UInt64S: { RETURN_INT_SWAP(uint64_t, NewBigInt); } break;
1913
- case PrimitiveKind::String: {
1914
- if (len >= 0) {
1915
- const char *str = *(const char **)ptr;
1916
- return str ? Napi::String::New(env, str, len) : env.Null();
1917
- } else {
1918
- const char *str = *(const char **)ptr;
1919
- return str ? Napi::String::New(env, str) : env.Null();
1920
- }
1921
- } break;
1922
- case PrimitiveKind::String16: {
1923
- if (len >= 0) {
1924
- const char16_t *str16 = *(const char16_t **)ptr;
1925
- return str16 ? Napi::String::New(env, str16, len) : env.Null();
1926
- } else {
1927
- const char16_t *str16 = *(const char16_t **)ptr;
1928
- return str16 ? Napi::String::New(env, str16) : env.Null();
1929
- }
1930
- } break;
1931
- case PrimitiveKind::Pointer:
1932
- case PrimitiveKind::Callback: {
1933
- void *ptr2 = *(void **)ptr;
1934
- return ptr2 ? Napi::External<void>::New(env, ptr2, [](Napi::Env, void *) {}) : env.Null();
1935
- } break;
1936
- case PrimitiveKind::Array: {
1937
- Napi::Value array = DecodeArray(env, ptr, type);
1938
- return array;
1939
- } break;
1940
- case PrimitiveKind::Record: {
1941
- Napi::Object obj = DecodeObject(env, ptr, type);
1942
- return obj;
1943
- } break;
1944
- case PrimitiveKind::Float32: {
1945
- float f = *(float *)ptr;
1946
- return Napi::Number::New(env, f);
1947
- } break;
1948
- case PrimitiveKind::Float64: {
1949
- double d = *(double *)ptr;
1950
- return Napi::Number::New(env, d);
1951
- } break;
1952
-
1953
- case PrimitiveKind::Prototype: {
1954
- ThrowError<Napi::TypeError>(env, "Cannot decode value of type %1", type->name);
1955
- return env.Null();
1956
- } break;
1957
- }
1958
-
1959
- #undef RETURN_BIGINT
1960
- #undef RETURN_INT
1961
-
1962
- return env.Null();
1983
+ Napi::Value ret = Decode(value, offset, type, len);
1984
+ return ret;
1963
1985
  }
1964
1986
 
1965
1987
  extern "C" void RelayCallback(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
1966
1988
  {
1967
1989
  if (RG_LIKELY(exec_call)) {
1968
- exec_call->RelaySafe(idx, own_sp, caller_sp, out_reg);
1990
+ exec_call->RelaySafe(idx, own_sp, caller_sp, false, out_reg);
1969
1991
  } else {
1970
1992
  // This happens if the callback pointer is called from a different thread
1971
1993
  // than the one that runs the FFI call (sync or async).
@@ -1985,8 +2007,9 @@ extern "C" void RelayCallback(Size idx, uint8_t *own_sp, uint8_t *caller_sp, Bac
1985
2007
  RG_DEFER_C(generation = trampoline->generation) { trampoline->generation = generation; };
1986
2008
  trampoline->generation = -1;
1987
2009
 
2010
+ // We set dispose_call to true so that the main thread will dispose of CallData itself
1988
2011
  CallData call(env, instance, mem);
1989
- call.RelaySafe(idx, own_sp, caller_sp, out_reg);
2012
+ call.RelaySafe(idx, own_sp, caller_sp, true, out_reg);
1990
2013
  }
1991
2014
  }
1992
2015
 
@@ -1998,6 +2021,8 @@ static void SetExports(Napi::Env env, Func func)
1998
2021
 
1999
2022
  func("struct", Napi::Function::New(env, CreatePaddedStructType));
2000
2023
  func("pack", Napi::Function::New(env, CreatePackedStructType));
2024
+ // func("union", Napi::Function::New(env, CreateUnionType));
2025
+ // func("Union", Napi::Function::New(env, InstantiateUnion));
2001
2026
  func("opaque", Napi::Function::New(env, CreateOpaqueType));
2002
2027
  func("pointer", Napi::Function::New(env, CreatePointerType));
2003
2028
  func("array", Napi::Function::New(env, CreateArrayType));
@@ -32,9 +32,6 @@ static const Size MaxParameters = 32;
32
32
  static const Size MaxOutParameters = 16;
33
33
  static const Size MaxTrampolines = 1024;
34
34
 
35
- extern const int TypeInfoMarker;
36
- extern const int CastMarker;
37
-
38
35
  enum class PrimitiveKind {
39
36
  Void,
40
37
  Bool,
@@ -56,6 +53,7 @@ enum class PrimitiveKind {
56
53
  String16,
57
54
  Pointer,
58
55
  Record,
56
+ Union,
59
57
  Array,
60
58
  Float32,
61
59
  Float64,
@@ -83,6 +81,7 @@ static const char *const PrimitiveKindNames[] = {
83
81
  "String16",
84
82
  "Pointer",
85
83
  "Record",
84
+ "Union",
86
85
  "Array",
87
86
  "Float32",
88
87
  "Float64",
@@ -96,13 +95,18 @@ struct FunctionInfo;
96
95
 
97
96
  typedef void DisposeFunc (Napi::Env env, const TypeInfo *type, const void *ptr);
98
97
 
99
- struct TypeInfo {
100
- enum class ArrayHint {
101
- Array,
102
- TypedArray,
103
- String
104
- };
98
+ enum class ArrayHint {
99
+ Array,
100
+ Typed,
101
+ String
102
+ };
103
+ static const char *const ArrayHintNames[] = {
104
+ "Array",
105
+ "Typed",
106
+ "String"
107
+ };
105
108
 
109
+ struct TypeInfo {
106
110
  const char *name;
107
111
 
108
112
  PrimitiveKind primitive;
@@ -120,6 +124,7 @@ struct TypeInfo {
120
124
  } ref;
121
125
  ArrayHint hint; // Array only
122
126
 
127
+ mutable Napi::FunctionReference construct; // Union only
123
128
  mutable Napi::ObjectReference defn;
124
129
 
125
130
  RG_HASHTABLE_HANDLER(TypeInfo, name);
@@ -174,6 +179,7 @@ struct ParameterInfo {
174
179
  bool use_memory; // Only used for return value on ARM32
175
180
  int8_t gpr_count;
176
181
  int8_t vec_count;
182
+ int8_t vec_bytes; // ARM64
177
183
  #elif defined(__i386__) || defined(_M_IX86)
178
184
  bool trivial; // Only matters for return value
179
185
  bool fast;
@@ -182,6 +188,7 @@ struct ParameterInfo {
182
188
  int8_t gpr_count;
183
189
  int8_t vec_count;
184
190
  bool gpr_first; // Only for structs
191
+ int8_t reg_size[2];
185
192
  #endif
186
193
  };
187
194
 
@@ -230,8 +237,9 @@ struct InstanceMemory {
230
237
 
231
238
  uint16_t generation; // Can wrap without risk
232
239
 
233
- int16_t depth;
240
+ std::atomic_bool busy;
234
241
  bool temporary;
242
+ int depth;
235
243
  };
236
244
 
237
245
  struct InstanceData {
@@ -18,20 +18,28 @@ declare module 'koffi' {
18
18
  interface IKoffiPointerCast { __brand: 'IKoffiPointerCast' }
19
19
  interface IKoffiRegisteredCallback { __brand: 'IKoffiRegisteredCallback' }
20
20
 
21
+ type PrimitiveKind = 'Void' | 'Bool' | 'Int8' | 'UInt8' | 'Int16' | 'Int16S' | 'UInt16' | 'UInt16S' |
22
+ 'Int32' | 'Int32S' | 'UInt32' | 'UInt32S' | 'Int64' | 'Int64S' | 'UInt64' | 'UInt64S' |
23
+ 'String' | 'String16' | 'Pointer' | 'Record' | 'Union' | 'Array' | 'Float32' | 'Float64' |
24
+ 'Prototype' | 'Callback';
25
+ type ArrayHint = 'Array' | 'Typed' | 'String';
26
+
21
27
  type TypeSpec = string | IKoffiCType;
22
28
  type TypeSpecWithAlignment = TypeSpec | [number, TypeSpec];
23
29
  type TypeInfo = {
24
30
  name: string;
25
- primitive: string;
31
+ primitive: PrimitiveKind;
26
32
  size: number;
27
33
  alignment: number;
28
34
  disposable: boolean;
29
- length: number;
30
- ref: IKoffiCType;
31
- members: Record<string, { name: string, type: IKoffiCType, offset: number }>;
35
+ length?: number;
36
+ hint?: ArrayHint;
37
+ ref?: IKoffiCType;
38
+ members?: Record<string, { name: string, type: IKoffiCType, offset: number }>;
32
39
  };
33
- type KoffiFunction = Function & {
34
- async: Function;
40
+ type KoffiFunction = {
41
+ (...args: any[]) : any;
42
+ async: (...args: any[]) => any;
35
43
  info: {
36
44
  name: string,
37
45
  arguments: IKoffiCType[],
@@ -39,6 +47,15 @@ declare module 'koffi' {
39
47
  };
40
48
  };
41
49
 
50
+ export type KoffiFunc<T extends (...args: any) => any> = T & {
51
+ async: (...args: [...Parameters<T>, (err: any, result: ReturnType<T>) => void]) => void;
52
+ info: {
53
+ name: string;
54
+ arguments: IKoffiCType[];
55
+ result: IKoffiCType;
56
+ };
57
+ };
58
+
42
59
  export interface IKoffiLib {
43
60
  func(definition: string): KoffiFunction;
44
61
  func(name: string, result: TypeSpec, arguments: TypeSpec[]): KoffiFunction;
@@ -58,10 +75,14 @@ declare module 'koffi' {
58
75
 
59
76
  export function struct(name: string, def: Record<string, TypeSpecWithAlignment>): IKoffiCType;
60
77
  export function struct(def: Record<string, TypeSpecWithAlignment>): IKoffiCType;
61
-
62
78
  export function pack(name: string, def: Record<string, TypeSpecWithAlignment>): IKoffiCType;
63
79
  export function pack(def: Record<string, TypeSpecWithAlignment>): IKoffiCType;
64
80
 
81
+ // export function union(name: string, def: Record<string, TypeSpecWithAlignment>): IKoffiCType;
82
+ // export function union(def: Record<string, TypeSpecWithAlignment>): IKoffiCType;
83
+
84
+ export function array(ref: TypeSpec, len: number, hint?: ArrayHint | null): IKoffiCType;
85
+
65
86
  export function opaque(name: string): IKoffiCType;
66
87
  export function opaque(): IKoffiCType;
67
88
 
@@ -13,12 +13,31 @@
13
13
 
14
14
  'use strict';
15
15
 
16
- if (process.versions.napi == null || process.versions.napi < 8)
17
- throw new Error('This platform does not support N-API 8');
18
-
16
+ const package = require('../package.json');
17
+ const cnoke = require('../../cnoke');
19
18
  const util = require('util');
20
19
 
21
- let filename = __dirname + '/../build/koffi.node';
20
+ if (process.versions.napi == null || process.versions.napi < 8) {
21
+ let major = parseInt(process.versions.node, 10);
22
+ let required = cnoke.get_napi_version(8, major);
23
+
24
+ if (required != null) {
25
+ throw new Error(`Project ${pkg.name} requires Node >= ${required} in the Node ${major}.x branch (N-API >= 8)`);
26
+ } else {
27
+ throw new Error(`Project ${pkg.name} does not support the Node ${major}.x branch (N-API < 8)`);
28
+ }
29
+ }
30
+
31
+ let arch = cnoke.determine_arch();
32
+ let filename = __dirname + `/../build/${package.version}/koffi_${process.platform}_${arch}/koffi.node`;
33
+
34
+ // Development build
35
+ if (!fs.existsSync(filename)) {
36
+ let alternative = __dirname + '/../build/koffi.node';
37
+ if (fs.existsSync(alternative))
38
+ filename = alternative;
39
+ }
40
+
22
41
  let native = require(filename);
23
42
 
24
43
  module.exports = {