koffi 2.3.4 → 2.3.5

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 (191) hide show
  1. package/CHANGELOG.md +18 -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 +2 -2
  6. package/src/core/libcc/libcc.cc +2 -2
  7. package/src/koffi/build/2.3.5/koffi_darwin_arm64.tar.gz +0 -0
  8. package/src/koffi/build/2.3.5/koffi_darwin_x64.tar.gz +0 -0
  9. package/src/koffi/build/2.3.5/koffi_freebsd_arm64.tar.gz +0 -0
  10. package/src/koffi/build/2.3.5/koffi_freebsd_ia32.tar.gz +0 -0
  11. package/src/koffi/build/2.3.5/koffi_freebsd_x64.tar.gz +0 -0
  12. package/src/koffi/build/2.3.5/koffi_linux_arm32hf.tar.gz +0 -0
  13. package/src/koffi/build/2.3.5/koffi_linux_arm64.tar.gz +0 -0
  14. package/src/koffi/build/2.3.5/koffi_linux_ia32.tar.gz +0 -0
  15. package/src/koffi/build/2.3.5/koffi_linux_riscv64hf64.tar.gz +0 -0
  16. package/src/koffi/build/2.3.5/koffi_linux_x64.tar.gz +0 -0
  17. package/src/koffi/build/2.3.5/koffi_openbsd_ia32.tar.gz +0 -0
  18. package/src/koffi/build/2.3.5/koffi_openbsd_x64.tar.gz +0 -0
  19. package/src/koffi/build/2.3.5/koffi_win32_arm64.tar.gz +0 -0
  20. package/src/koffi/build/2.3.5/koffi_win32_ia32.tar.gz +0 -0
  21. package/src/koffi/build/2.3.5/koffi_win32_x64.tar.gz +0 -0
  22. package/src/koffi/src/abi_arm32.cc +43 -14
  23. package/src/koffi/src/abi_arm64.cc +95 -21
  24. package/src/koffi/src/abi_riscv64.cc +125 -64
  25. package/src/koffi/src/abi_x64_sysv.cc +38 -20
  26. package/src/koffi/src/abi_x64_win.cc +11 -5
  27. package/src/koffi/src/abi_x86.cc +14 -7
  28. package/src/koffi/src/call.cc +114 -44
  29. package/src/koffi/src/call.hh +6 -4
  30. package/src/koffi/src/ffi.cc +172 -147
  31. package/src/koffi/src/ffi.hh +18 -10
  32. package/src/koffi/src/index.d.ts +28 -7
  33. package/src/koffi/src/util.cc +261 -69
  34. package/src/koffi/src/util.hh +34 -8
  35. package/vendor/node-addon-api/CHANGELOG.md +122 -9
  36. package/vendor/node-addon-api/CONTRIBUTING.md +10 -10
  37. package/vendor/node-addon-api/README.md +36 -12
  38. package/vendor/node-addon-api/benchmark/function_args.cc +95 -62
  39. package/vendor/node-addon-api/benchmark/function_args.js +6 -6
  40. package/vendor/node-addon-api/benchmark/index.js +1 -1
  41. package/vendor/node-addon-api/benchmark/property_descriptor.cc +27 -34
  42. package/vendor/node-addon-api/benchmark/property_descriptor.js +5 -4
  43. package/vendor/node-addon-api/doc/async_operations.md +1 -1
  44. package/vendor/node-addon-api/doc/async_worker_variants.md +23 -2
  45. package/vendor/node-addon-api/doc/cmake-js.md +1 -1
  46. package/vendor/node-addon-api/doc/error_handling.md +3 -3
  47. package/vendor/node-addon-api/doc/external.md +7 -0
  48. package/vendor/node-addon-api/doc/handle_scope.md +14 -0
  49. package/vendor/node-addon-api/doc/hierarchy.md +1 -1
  50. package/vendor/node-addon-api/doc/object.md +27 -0
  51. package/vendor/node-addon-api/index.js +3 -3
  52. package/vendor/node-addon-api/napi-inl.deprecated.h +121 -127
  53. package/vendor/node-addon-api/napi-inl.h +1178 -1144
  54. package/vendor/node-addon-api/napi.h +2786 -2675
  55. package/vendor/node-addon-api/package.json +42 -1
  56. package/vendor/node-addon-api/test/addon.cc +8 -6
  57. package/vendor/node-addon-api/test/addon_build/index.js +9 -9
  58. package/vendor/node-addon-api/test/addon_build/tpl/addon.cc +2 -1
  59. package/vendor/node-addon-api/test/addon_build/tpl/index.js +4 -4
  60. package/vendor/node-addon-api/test/addon_data.cc +12 -13
  61. package/vendor/node-addon-api/test/array_buffer.js +3 -2
  62. package/vendor/node-addon-api/test/async_progress_queue_worker.cc +13 -3
  63. package/vendor/node-addon-api/test/async_progress_queue_worker.js +5 -5
  64. package/vendor/node-addon-api/test/async_progress_worker.cc +65 -9
  65. package/vendor/node-addon-api/test/async_progress_worker.js +14 -9
  66. package/vendor/node-addon-api/test/async_worker.cc +236 -3
  67. package/vendor/node-addon-api/test/async_worker.js +122 -37
  68. package/vendor/node-addon-api/test/async_worker_nocallback.js +9 -3
  69. package/vendor/node-addon-api/test/async_worker_persistent.js +2 -2
  70. package/vendor/node-addon-api/test/basic_types/array.js +3 -4
  71. package/vendor/node-addon-api/test/basic_types/boolean.cc +4 -2
  72. package/vendor/node-addon-api/test/basic_types/boolean.js +1 -2
  73. package/vendor/node-addon-api/test/basic_types/number.cc +12 -6
  74. package/vendor/node-addon-api/test/basic_types/number.js +19 -18
  75. package/vendor/node-addon-api/test/basic_types/value.cc +52 -1
  76. package/vendor/node-addon-api/test/basic_types/value.js +44 -21
  77. package/vendor/node-addon-api/test/bigint.cc +2 -1
  78. package/vendor/node-addon-api/test/binding.cc +11 -5
  79. package/vendor/node-addon-api/test/binding.gyp +3 -1
  80. package/vendor/node-addon-api/test/buffer.cc +46 -38
  81. package/vendor/node-addon-api/test/buffer.js +12 -12
  82. package/vendor/node-addon-api/test/callbackInfo.cc +27 -0
  83. package/vendor/node-addon-api/test/callbackInfo.js +9 -0
  84. package/vendor/node-addon-api/test/callbackscope.cc +19 -2
  85. package/vendor/node-addon-api/test/callbackscope.js +20 -20
  86. package/vendor/node-addon-api/test/common/index.js +37 -4
  87. package/vendor/node-addon-api/test/dataview/dataview.js +5 -5
  88. package/vendor/node-addon-api/test/dataview/dataview_read_write.js +14 -12
  89. package/vendor/node-addon-api/test/date.cc +2 -1
  90. package/vendor/node-addon-api/test/date.js +2 -2
  91. package/vendor/node-addon-api/test/env_cleanup.cc +12 -0
  92. package/vendor/node-addon-api/test/env_cleanup.js +38 -39
  93. package/vendor/node-addon-api/test/error.cc +6 -5
  94. package/vendor/node-addon-api/test/error_terminating_environment.js +64 -60
  95. package/vendor/node-addon-api/test/external.cc +36 -32
  96. package/vendor/node-addon-api/test/external.js +43 -46
  97. package/vendor/node-addon-api/test/function.cc +58 -44
  98. package/vendor/node-addon-api/test/function.js +4 -0
  99. package/vendor/node-addon-api/test/function_reference.cc +15 -13
  100. package/vendor/node-addon-api/test/globalObject/global_object_delete_property.js +50 -53
  101. package/vendor/node-addon-api/test/globalObject/global_object_get_property.js +33 -34
  102. package/vendor/node-addon-api/test/globalObject/global_object_has_own_property.js +38 -40
  103. package/vendor/node-addon-api/test/globalObject/global_object_set_property.js +47 -49
  104. package/vendor/node-addon-api/test/handlescope.cc +29 -3
  105. package/vendor/node-addon-api/test/handlescope.js +5 -3
  106. package/vendor/node-addon-api/test/index.js +1 -5
  107. package/vendor/node-addon-api/test/maybe/check.cc +49 -3
  108. package/vendor/node-addon-api/test/maybe/index.js +19 -7
  109. package/vendor/node-addon-api/test/memory_management.cc +9 -8
  110. package/vendor/node-addon-api/test/memory_management.js +2 -2
  111. package/vendor/node-addon-api/test/movable_callbacks.js +2 -2
  112. package/vendor/node-addon-api/test/name.js +3 -3
  113. package/vendor/node-addon-api/test/napi_child.js +2 -2
  114. package/vendor/node-addon-api/test/object/delete_property.js +7 -7
  115. package/vendor/node-addon-api/test/object/finalizer.cc +13 -12
  116. package/vendor/node-addon-api/test/object/finalizer.js +2 -2
  117. package/vendor/node-addon-api/test/object/get_property.js +6 -6
  118. package/vendor/node-addon-api/test/object/has_own_property.js +3 -3
  119. package/vendor/node-addon-api/test/object/has_property.js +4 -4
  120. package/vendor/node-addon-api/test/object/object.cc +191 -111
  121. package/vendor/node-addon-api/test/object/object.js +53 -52
  122. package/vendor/node-addon-api/test/object/object_deprecated.cc +24 -20
  123. package/vendor/node-addon-api/test/object/object_deprecated.js +3 -8
  124. package/vendor/node-addon-api/test/object/object_freeze_seal.js +54 -54
  125. package/vendor/node-addon-api/test/object/object_type_tag.cc +39 -0
  126. package/vendor/node-addon-api/test/object/object_type_tag.js +55 -0
  127. package/vendor/node-addon-api/test/object/subscript_operator.js +2 -2
  128. package/vendor/node-addon-api/test/object_reference.js +100 -100
  129. package/vendor/node-addon-api/test/objectwrap.cc +41 -34
  130. package/vendor/node-addon-api/test/objectwrap.js +23 -19
  131. package/vendor/node-addon-api/test/objectwrap_constructor_exception.cc +5 -5
  132. package/vendor/node-addon-api/test/objectwrap_constructor_exception.js +1 -1
  133. package/vendor/node-addon-api/test/objectwrap_multiple_inheritance.cc +7 -7
  134. package/vendor/node-addon-api/test/objectwrap_multiple_inheritance.js +1 -1
  135. package/vendor/node-addon-api/test/objectwrap_removewrap.js +24 -32
  136. package/vendor/node-addon-api/test/objectwrap_worker_thread.js +5 -4
  137. package/vendor/node-addon-api/test/promise.cc +7 -0
  138. package/vendor/node-addon-api/test/promise.js +3 -1
  139. package/vendor/node-addon-api/test/reference.cc +1 -1
  140. package/vendor/node-addon-api/test/reference.js +2 -2
  141. package/vendor/node-addon-api/test/run_script.cc +1 -1
  142. package/vendor/node-addon-api/test/symbol.js +59 -66
  143. package/vendor/node-addon-api/test/testUtil.js +6 -6
  144. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function.cc +64 -29
  145. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function.js +71 -34
  146. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_ctx.cc +111 -19
  147. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_ctx.js +2 -1
  148. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_existing_tsfn.cc +36 -26
  149. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_existing_tsfn.js +5 -5
  150. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_ptr.cc +3 -2
  151. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_ptr.js +1 -1
  152. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_sum.cc +47 -32
  153. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_sum.js +3 -3
  154. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_unref.cc +22 -9
  155. package/vendor/node-addon-api/test/threadsafe_function/threadsafe_function_unref.js +76 -31
  156. package/vendor/node-addon-api/test/thunking_manual.cc +61 -74
  157. package/vendor/node-addon-api/test/thunking_manual.js +6 -7
  158. package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function.cc +20 -20
  159. package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function.js +19 -19
  160. package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_ctx.cc +57 -5
  161. package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_ctx.js +2 -0
  162. package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_existing_tsfn.js +5 -5
  163. package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_ptr.cc +5 -1
  164. package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_ptr.js +4 -3
  165. package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_sum.js +3 -3
  166. package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_unref.cc +14 -0
  167. package/vendor/node-addon-api/test/typed_threadsafe_function/typed_threadsafe_function_unref.js +76 -31
  168. package/vendor/node-addon-api/test/typedarray-bigint.js +2 -2
  169. package/vendor/node-addon-api/test/typedarray.cc +263 -70
  170. package/vendor/node-addon-api/test/typedarray.js +44 -10
  171. package/vendor/node-addon-api/test/version_management.cc +16 -15
  172. package/vendor/node-addon-api/test/version_management.js +18 -20
  173. package/vendor/node-addon-api/tools/check-napi.js +13 -14
  174. package/vendor/node-addon-api/tools/conversion.js +161 -169
  175. package/vendor/node-addon-api/tools/eslint-format.js +9 -1
  176. package/vendor/node-addon-api/unit-test/README.md +4 -4
  177. package/src/koffi/build/2.3.4/koffi_darwin_arm64.tar.gz +0 -0
  178. package/src/koffi/build/2.3.4/koffi_darwin_x64.tar.gz +0 -0
  179. package/src/koffi/build/2.3.4/koffi_freebsd_arm64.tar.gz +0 -0
  180. package/src/koffi/build/2.3.4/koffi_freebsd_ia32.tar.gz +0 -0
  181. package/src/koffi/build/2.3.4/koffi_freebsd_x64.tar.gz +0 -0
  182. package/src/koffi/build/2.3.4/koffi_linux_arm32hf.tar.gz +0 -0
  183. package/src/koffi/build/2.3.4/koffi_linux_arm64.tar.gz +0 -0
  184. package/src/koffi/build/2.3.4/koffi_linux_ia32.tar.gz +0 -0
  185. package/src/koffi/build/2.3.4/koffi_linux_riscv64hf64.tar.gz +0 -0
  186. package/src/koffi/build/2.3.4/koffi_linux_x64.tar.gz +0 -0
  187. package/src/koffi/build/2.3.4/koffi_openbsd_ia32.tar.gz +0 -0
  188. package/src/koffi/build/2.3.4/koffi_openbsd_x64.tar.gz +0 -0
  189. package/src/koffi/build/2.3.4/koffi_win32_arm64.tar.gz +0 -0
  190. package/src/koffi/build/2.3.4/koffi_win32_ia32.tar.gz +0 -0
  191. package/src/koffi/build/2.3.4/koffi_win32_x64.tar.gz +0 -0
@@ -64,11 +64,21 @@ extern "C" napi_value CallSwitchStack(Napi::Function *func, size_t argc, napi_va
64
64
 
65
65
  #include "abi_trampolines.inc"
66
66
 
67
- static void AnalyseParameter(ParameterInfo *param, int gpr_avail, int vec_avail)
67
+ static inline void ExpandPair(const uint8_t raw[16], int size1, int size2, uint64_t out_regs[2])
68
68
  {
69
- gpr_avail = std::min(2, gpr_avail);
70
- vec_avail = std::min(2, vec_avail);
69
+ memcpy(out_regs + 0, raw, size1);
70
+ memcpy(out_regs + 1, raw + size1, size2);
71
+ }
71
72
 
73
+ static inline void CompactPair(const uint64_t regs[2], int size1, int size2, uint8_t out_raw[16])
74
+ {
75
+ memcpy(out_raw, regs + 0, size1);
76
+ memcpy(out_raw + size1, regs + 1, size2);
77
+ }
78
+
79
+ static void AnalyseParameter(ParameterInfo *param, int gpr_avail, int vec_avail)
80
+ {
81
+ // Too big, pass pointer to struct
72
82
  if (param->type->size > 16) {
73
83
  param->gpr_count = gpr_avail ? 1 : 0;
74
84
  param->use_memory = true;
@@ -76,36 +86,55 @@ static void AnalyseParameter(ParameterInfo *param, int gpr_avail, int vec_avail)
76
86
  return;
77
87
  }
78
88
 
79
- int gpr_count = 0;
80
- int vec_count = 0;
81
- bool gpr_first = false;
89
+ gpr_avail = std::min(2, gpr_avail);
90
+ vec_avail = std::min(2, vec_avail);
82
91
 
83
- AnalyseFlat(param->type, [&](const TypeInfo *type, int offset, int count) {
84
92
  #if defined(__riscv_float_abi_double)
85
- bool fp = IsFloat(type);
93
+ if (param->type->primitive != PrimitiveKind::Union) {
94
+ int gpr_count = 0;
95
+ int vec_count = 0;
96
+ bool gpr_first = false;
97
+
98
+ AnalyseFlat(param->type, [&](const TypeInfo *type, int offset, int count) {
99
+ if (IsFloat(type)) {
100
+ vec_count += count;
101
+ } else {
102
+ gpr_count += count;
103
+ gpr_first |= !vec_count;
104
+ }
105
+
106
+ // We'll reset reg_size if the following conditions don't match,
107
+ // such as having more than two values.
108
+ param->reg_size[offset % 2] = (int8_t)type->size;
109
+ });
110
+
111
+ // Pass mixed float-integer structs in one GPR and one FP register
112
+ if (gpr_count == 1 && vec_count == 1 && gpr_avail && vec_avail) {
113
+ param->gpr_count = 1;
114
+ param->vec_count = 1;
115
+ param->gpr_first = gpr_first;
116
+
117
+ return;
118
+ }
119
+
120
+ // HFA rules
121
+ if (vec_count && !gpr_count && vec_count <= vec_avail) {
122
+ param->vec_count = vec_count;
123
+ return;
124
+ }
125
+ }
86
126
  #elif defined(__riscv_float_abi_soft)
87
- bool fp = false;
127
+ // Use integer conventions
88
128
  #else
89
- #error The RISC-V single-precision float ABI (LP64F) is not supported
129
+ #error The RISC-V single-precision float ABI (LP64F) is not supported
90
130
  #endif
91
131
 
92
- if (fp) {
93
- vec_count += count;
94
- } else {
95
- gpr_count += count;
96
- gpr_first |= !vec_count;
97
- }
98
- });
99
-
100
- if (gpr_count == 1 && vec_count == 1 && gpr_avail && vec_avail) {
101
- param->gpr_count = 1;
102
- param->vec_count = 1;
103
- param->gpr_first = gpr_first;
104
- } else if (vec_count && !gpr_count && vec_count <= vec_avail) {
105
- param->vec_count = vec_count;
106
- } else if (gpr_avail) {
107
- param->gpr_count = (param->type->size + 7) / 8;
108
- param->gpr_first = true;
132
+ param->reg_size[0] = 8;
133
+ param->reg_size[1] = 8;
134
+
135
+ if (gpr_avail) {
136
+ param->gpr_count = std::min(gpr_avail, (param->type->size + 7) / 8);
137
+ param->gpr_first = param->gpr_count;
109
138
  }
110
139
  }
111
140
 
@@ -222,7 +251,8 @@ bool CallData::Prepare(const FunctionInfo *func, const Napi::CallbackInfo &info)
222
251
 
223
252
  *(void **)((param.gpr_count ? gpr_ptr : args_ptr)++) = ptr;
224
253
  } break;
225
- case PrimitiveKind::Record: {
254
+ case PrimitiveKind::Record:
255
+ case PrimitiveKind::Union: {
226
256
  if (RG_UNLIKELY(!IsObject(value))) {
227
257
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
228
258
  return false;
@@ -233,25 +263,34 @@ bool CallData::Prepare(const FunctionInfo *func, const Napi::CallbackInfo &info)
233
263
  if (!param.use_memory) {
234
264
  RG_ASSERT(param.type->size <= 16);
235
265
 
236
- // Split float or mixed int-float structs to registers
237
- int realign = param.vec_count ? 8 : 0;
238
-
239
- uint64_t buf[2] = { 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull };
240
- if (!PushObject(obj, param.type, (uint8_t *)buf, realign))
241
- return false;
242
- uint64_t *ptr = buf;
266
+ uint64_t regs[2] = { 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull };
267
+ {
268
+ uint8_t buf[16] = {};
269
+ if (!PushObject(obj, param.type, buf))
270
+ return false;
271
+ ExpandPair(buf, param.reg_size[0], param.reg_size[1], regs);
272
+ }
243
273
 
244
274
  if (param.gpr_first) {
245
- *(gpr_ptr++) = *(ptr++);
246
- *((param.vec_count ? vec_ptr : gpr_ptr)++) = *(ptr++);
247
- gpr_ptr -= (param.gpr_count == 1);
275
+ *(gpr_ptr++) = regs[0];
276
+ if (param.gpr_count == 2) {
277
+ *(gpr_ptr++) = regs[1];
278
+ } else if (param.vec_count == 1) {
279
+ *(vec_ptr++) = regs[1];
280
+ }
281
+
282
+ args_ptr = std::max(gpr_ptr, args_ptr);
248
283
  } else if (param.vec_count) {
249
- *(vec_ptr++) = *(ptr++);
250
- *((param.gpr_count ? gpr_ptr : vec_ptr)++) = *(ptr++);
284
+ *(vec_ptr++) = regs[0];
285
+ if (param.vec_count == 2) {
286
+ *(vec_ptr++) = regs[1];
287
+ } else if (param.gpr_count == 1) {
288
+ *(gpr_ptr++) = regs[1];
289
+ }
251
290
  } else {
252
291
  RG_ASSERT(param.type->align <= 8);
253
292
 
254
- memcpy_safe(args_ptr, ptr, param.type->size);
293
+ memcpy_safe(args_ptr, regs, param.type->size);
255
294
  args_ptr += (param.type->size + 7) / 8;
256
295
  }
257
296
  } else {
@@ -370,7 +409,8 @@ void CallData::Execute(const FunctionInfo *func)
370
409
  case PrimitiveKind::String16:
371
410
  case PrimitiveKind::Pointer:
372
411
  case PrimitiveKind::Callback: { result.u64 = PERFORM_CALL(GG).a0; } break;
373
- case PrimitiveKind::Record: {
412
+ case PrimitiveKind::Record:
413
+ case PrimitiveKind::Union: {
374
414
  if (func->ret.gpr_first && !func->ret.vec_count) {
375
415
  A0A1Ret ret = PERFORM_CALL(GG);
376
416
  memcpy(&result.buf, &ret, RG_SIZE(ret));
@@ -435,15 +475,16 @@ Napi::Value CallData::Complete(const FunctionInfo *func)
435
475
  return env.Null();
436
476
  }
437
477
  } break;
438
- case PrimitiveKind::Record: {
439
- if (func->ret.vec_count) { // HFA
440
- Napi::Object obj = DecodeObject(env, (const uint8_t *)&result.buf, func->ret.type, 8);
478
+ case PrimitiveKind::Record:
479
+ case PrimitiveKind::Union: {
480
+ if (return_ptr) {
481
+ Napi::Object obj = DecodeObject(env, return_ptr, func->ret.type);
441
482
  return obj;
442
483
  } else {
443
- const uint8_t *ptr = return_ptr ? (const uint8_t *)return_ptr
444
- : (const uint8_t *)&result.buf;
484
+ uint8_t buf[16] = {};
485
+ CompactPair(&result.u64, func->ret.reg_size[0], func->ret.reg_size[1], buf);
445
486
 
446
- Napi::Object obj = DecodeObject(env, ptr, func->ret.type);
487
+ Napi::Object obj = DecodeObject(env, buf, func->ret.type);
447
488
  return obj;
448
489
  }
449
490
  } break;
@@ -624,29 +665,29 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, bool async,
624
665
  param.type->dispose(env, param.type, ptr2);
625
666
  }
626
667
  } break;
627
- case PrimitiveKind::Record: {
668
+ case PrimitiveKind::Record:
669
+ case PrimitiveKind::Union: {
628
670
  if (!param.use_memory) {
629
- uint64_t buf[2] = {};
630
- uint64_t *ptr = buf;
671
+ uint64_t regs[2] = {};
631
672
 
632
673
  if (param.gpr_first) {
633
- *(ptr++) = *(gpr_ptr++);
634
- *(ptr++) = *((param.vec_count ? vec_ptr : gpr_ptr)++);
674
+ regs[0] = *(gpr_ptr++);
675
+ regs[1] = *((param.vec_count ? vec_ptr : gpr_ptr)++);
635
676
  gpr_ptr -= (param.gpr_count == 1);
636
677
  } else if (param.vec_count) {
637
- *(ptr++) = *(vec_ptr++);
638
- *(ptr++) = *((param.gpr_count ? gpr_ptr : vec_ptr)++);
678
+ regs[0] = *(vec_ptr++);
679
+ regs[1] = *((param.gpr_count ? gpr_ptr : vec_ptr)++);
639
680
  } else {
640
681
  RG_ASSERT(param.type->align <= 8);
641
682
 
642
- memcpy_safe(ptr, args_ptr, param.type->size);
683
+ memcpy_safe(regs, args_ptr, param.type->size);
643
684
  args_ptr += (param.type->size + 7) / 8;
644
685
  }
645
686
 
646
- // Reassemble float or mixed int-float structs from registers
647
- int realign = param.vec_count ? 8 : 0;
687
+ uint8_t buf[16] = {};
688
+ CompactPair(regs, param.reg_size[0], param.reg_size[1], buf);
648
689
 
649
- Napi::Object obj = DecodeObject(env, (const uint8_t *)buf, param.type, realign);
690
+ Napi::Object obj = DecodeObject(env, buf, param.type);
650
691
  arguments.Append(obj);
651
692
  } else {
652
693
  uint8_t *ptr = *(uint8_t **)((param.gpr_count ? gpr_ptr : args_ptr)++);
@@ -768,7 +809,8 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, bool async,
768
809
 
769
810
  if (CheckValueTag(instance, value, type->ref.marker)) {
770
811
  ptr = value.As<Napi::External<uint8_t>>().Data();
771
- } else if (IsObject(value) && type->ref.type->primitive == PrimitiveKind::Record) {
812
+ } else if (IsObject(value) && (type->ref.type->primitive == PrimitiveKind::Record ||
813
+ type->ref.type->primitive == PrimitiveKind::Union)) {
772
814
  Napi::Object obj = value.As<Napi::Object>();
773
815
 
774
816
  ptr = AllocHeap(type->ref.type->size, 16);
@@ -784,7 +826,8 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, bool async,
784
826
 
785
827
  out_reg->a0 = (uint64_t)ptr;
786
828
  } break;
787
- case PrimitiveKind::Record: {
829
+ case PrimitiveKind::Record:
830
+ case PrimitiveKind::Union: {
788
831
  if (RG_UNLIKELY(!IsObject(value))) {
789
832
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
790
833
  return;
@@ -796,10 +839,28 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, bool async,
796
839
  if (!PushObject(obj, type, return_ptr))
797
840
  return;
798
841
  out_reg->a0 = (uint64_t)return_ptr;
799
- } else if (proto->ret.vec_count) { // HFA
800
- PushObject(obj, type, (uint8_t *)&out_reg->fa0, 8);
801
842
  } else {
802
- PushObject(obj, type, (uint8_t *)&out_reg->a0);
843
+ uint64_t regs[2] = { 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull };
844
+ {
845
+ uint8_t buf[16] = {};
846
+ if (!PushObject(obj, type, buf))
847
+ return;
848
+ ExpandPair(buf, proto->ret.reg_size[0], proto->ret.reg_size[1], regs);
849
+ }
850
+
851
+ if (proto->ret.gpr_first && !proto->ret.vec_count) {
852
+ out_reg->a0 = regs[0];
853
+ out_reg->a1 = regs[1];
854
+ } else if (proto->ret.gpr_first) {
855
+ out_reg->a0 = regs[0];
856
+ out_reg->fa0 = *(double *)&regs[1];
857
+ } else if (proto->ret.vec_count == 2) {
858
+ out_reg->fa0 = *(double *)&regs[0];
859
+ out_reg->fa1 = *(double *)&regs[1];
860
+ } else {
861
+ out_reg->fa0 = *(double *)&regs[0];
862
+ out_reg->a0 = regs[1];
863
+ }
803
864
  }
804
865
  } break;
805
866
  case PrimitiveKind::Array: { RG_UNREACHABLE(); } break;
@@ -132,6 +132,20 @@ static Size ClassifyType(const TypeInfo *type, Size offset, Span<RegisterClass>
132
132
 
133
133
  return (offset + 7) / 8;
134
134
  } break;
135
+ case PrimitiveKind::Union: {
136
+ if (type->size > 64) {
137
+ classes[0] = MergeClasses(classes[0], RegisterClass::Memory);
138
+ return 1;
139
+ }
140
+
141
+ for (const RecordMember &member: type->members) {
142
+ Size start = offset / 8;
143
+ ClassifyType(member.type, offset % 8, classes.Take(start, classes.len - start));
144
+ }
145
+ offset += type->size;
146
+
147
+ return (offset + 7) / 8;
148
+ } break;
135
149
  case PrimitiveKind::Array: {
136
150
  if (type->size > 64) {
137
151
  classes[0] = MergeClasses(classes[0], RegisterClass::Memory);
@@ -310,7 +324,8 @@ bool CallData::Prepare(const FunctionInfo *func, const Napi::CallbackInfo &info)
310
324
 
311
325
  *(void **)((param.gpr_count ? gpr_ptr : args_ptr)++) = ptr;
312
326
  } break;
313
- case PrimitiveKind::Record: {
327
+ case PrimitiveKind::Record:
328
+ case PrimitiveKind::Union: {
314
329
  if (RG_UNLIKELY(!IsObject(value))) {
315
330
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
316
331
  return false;
@@ -324,21 +339,20 @@ bool CallData::Prepare(const FunctionInfo *func, const Napi::CallbackInfo &info)
324
339
  uint64_t buf[2] = {};
325
340
  if (!PushObject(obj, param.type, (uint8_t *)buf))
326
341
  return false;
327
- uint64_t *ptr = buf;
328
342
 
329
343
  if (param.gpr_first) {
330
- *(gpr_ptr++) = *(ptr++);
344
+ *(gpr_ptr++) = buf[0];
331
345
  if (param.gpr_count == 2) {
332
- *(gpr_ptr++) = *(ptr++);
346
+ *(gpr_ptr++) = buf[1];
333
347
  } else if (param.xmm_count == 1) {
334
- *(xmm_ptr++) = *(ptr++);
348
+ *(xmm_ptr++) = buf[1];
335
349
  }
336
350
  } else {
337
- *(xmm_ptr++) = *(ptr++);
351
+ *(xmm_ptr++) = buf[0];
338
352
  if (param.xmm_count == 2) {
339
- *(xmm_ptr++) = *(ptr++);
353
+ *(xmm_ptr++) = buf[1];
340
354
  } else if (param.gpr_count == 1) {
341
- *(gpr_ptr++) = *(ptr++);
355
+ *(gpr_ptr++) = buf[1];
342
356
  }
343
357
  }
344
358
  } else if (param.use_memory) {
@@ -434,7 +448,8 @@ void CallData::Execute(const FunctionInfo *func)
434
448
  case PrimitiveKind::String16:
435
449
  case PrimitiveKind::Pointer:
436
450
  case PrimitiveKind::Callback: { result.u64 = PERFORM_CALL(GG).rax; } break;
437
- case PrimitiveKind::Record: {
451
+ case PrimitiveKind::Record:
452
+ case PrimitiveKind::Union: {
438
453
  if (func->ret.gpr_first && !func->ret.xmm_count) {
439
454
  RaxRdxRet ret = PERFORM_CALL(GG);
440
455
  memcpy(&result.buf, &ret, RG_SIZE(ret));
@@ -499,7 +514,8 @@ Napi::Value CallData::Complete(const FunctionInfo *func)
499
514
  return env.Null();
500
515
  }
501
516
  } break;
502
- case PrimitiveKind::Record: {
517
+ case PrimitiveKind::Record:
518
+ case PrimitiveKind::Union: {
503
519
  const uint8_t *ptr = return_ptr ? (const uint8_t *)return_ptr
504
520
  : (const uint8_t *)&result.buf;
505
521
 
@@ -683,26 +699,26 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, bool async,
683
699
  param.type->dispose(env, param.type, ptr2);
684
700
  }
685
701
  } break;
686
- case PrimitiveKind::Record: {
702
+ case PrimitiveKind::Record:
703
+ case PrimitiveKind::Union: {
687
704
  if (param.gpr_count || param.xmm_count) {
688
705
  RG_ASSERT(param.type->size <= 16);
689
706
 
690
707
  uint64_t buf[2] = {};
691
- uint64_t *ptr = buf;
692
708
 
693
709
  if (param.gpr_first) {
694
- *(ptr++) = *(gpr_ptr++);
710
+ buf[0] = *(gpr_ptr++);
695
711
  if (param.gpr_count == 2) {
696
- *(ptr++) = *(gpr_ptr++);
712
+ buf[1] = *(gpr_ptr++);
697
713
  } else if (param.xmm_count == 1) {
698
- *(ptr++) = *(xmm_ptr++);
714
+ buf[1] = *(xmm_ptr++);
699
715
  }
700
716
  } else {
701
- *(ptr++) = *(xmm_ptr++);
717
+ buf[0] = *(xmm_ptr++);
702
718
  if (param.xmm_count == 2) {
703
- *(ptr++) = *(xmm_ptr++);
719
+ buf[1] = *(xmm_ptr++);
704
720
  } else if (param.gpr_count == 1) {
705
- *(ptr++) = *(gpr_ptr++);
721
+ buf[1] = *(gpr_ptr++);
706
722
  }
707
723
  }
708
724
 
@@ -816,7 +832,8 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, bool async,
816
832
 
817
833
  if (CheckValueTag(instance, value, type->ref.marker)) {
818
834
  ptr = value.As<Napi::External<uint8_t>>().Data();
819
- } else if (IsObject(value) && type->ref.type->primitive == PrimitiveKind::Record) {
835
+ } else if (IsObject(value) && (type->ref.type->primitive == PrimitiveKind::Record ||
836
+ type->ref.type->primitive == PrimitiveKind::Union)) {
820
837
  Napi::Object obj = value.As<Napi::Object>();
821
838
 
822
839
  ptr = AllocHeap(type->ref.type->size, 16);
@@ -832,7 +849,8 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, bool async,
832
849
 
833
850
  out_reg->rax = (uint64_t)ptr;
834
851
  } break;
835
- case PrimitiveKind::Record: {
852
+ case PrimitiveKind::Record:
853
+ case PrimitiveKind::Union: {
836
854
  if (RG_UNLIKELY(!IsObject(value))) {
837
855
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
838
856
  return;
@@ -143,7 +143,8 @@ bool CallData::Prepare(const FunctionInfo *func, const Napi::CallbackInfo &info)
143
143
 
144
144
  *(void **)(args_ptr++) = ptr;
145
145
  } break;
146
- case PrimitiveKind::Record: {
146
+ case PrimitiveKind::Record:
147
+ case PrimitiveKind::Union: {
147
148
  if (RG_UNLIKELY(!IsObject(value))) {
148
149
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
149
150
  return false;
@@ -261,6 +262,7 @@ void CallData::Execute(const FunctionInfo *func)
261
262
  case PrimitiveKind::String16:
262
263
  case PrimitiveKind::Pointer:
263
264
  case PrimitiveKind::Record:
265
+ case PrimitiveKind::Union:
264
266
  case PrimitiveKind::Callback: { result.u64 = PERFORM_CALL(G); } break;
265
267
  case PrimitiveKind::Array: { RG_UNREACHABLE(); } break;
266
268
  case PrimitiveKind::Float32: { result.f = PERFORM_CALL(F); } break;
@@ -312,7 +314,8 @@ Napi::Value CallData::Complete(const FunctionInfo *func)
312
314
  return env.Null();
313
315
  }
314
316
  } break;
315
- case PrimitiveKind::Record: {
317
+ case PrimitiveKind::Record:
318
+ case PrimitiveKind::Union: {
316
319
  const uint8_t *ptr = return_ptr ? (const uint8_t *)return_ptr
317
320
  : (const uint8_t *)&result.buf;
318
321
 
@@ -529,7 +532,8 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, bool async,
529
532
  param.type->dispose(env, param.type, ptr2);
530
533
  }
531
534
  } break;
532
- case PrimitiveKind::Record: {
535
+ case PrimitiveKind::Record:
536
+ case PrimitiveKind::Union: {
533
537
  uint8_t *ptr;
534
538
  if (param.regular) {
535
539
  ptr = (uint8_t *)(j < 4 ? gpr_ptr + j : args_ptr);
@@ -641,7 +645,8 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, bool async,
641
645
 
642
646
  if (CheckValueTag(instance, value, type->ref.marker)) {
643
647
  ptr = value.As<Napi::External<uint8_t>>().Data();
644
- } else if (IsObject(value) && type->ref.type->primitive == PrimitiveKind::Record) {
648
+ } else if (IsObject(value) && (type->ref.type->primitive == PrimitiveKind::Record ||
649
+ type->ref.type->primitive == PrimitiveKind::Union)) {
645
650
  Napi::Object obj = value.As<Napi::Object>();
646
651
 
647
652
  ptr = AllocHeap(type->ref.type->size, 16);
@@ -657,7 +662,8 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, bool async,
657
662
 
658
663
  out_reg->rax = (uint64_t)ptr;
659
664
  } break;
660
- case PrimitiveKind::Record: {
665
+ case PrimitiveKind::Record:
666
+ case PrimitiveKind::Union: {
661
667
  if (RG_UNLIKELY(!IsObject(value))) {
662
668
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
663
669
  return;
@@ -61,7 +61,8 @@ bool AnalyseFunction(Napi::Env env, InstanceData *instance, FunctionInfo *func)
61
61
  (func->convention == CallConvention::Thiscall) ? 1 : 0;
62
62
  func->fast = fast;
63
63
 
64
- if (func->ret.type->primitive != PrimitiveKind::Record) {
64
+ if (func->ret.type->primitive != PrimitiveKind::Record &&
65
+ func->ret.type->primitive != PrimitiveKind::Union) {
65
66
  func->ret.trivial = true;
66
67
  #if defined(_WIN32) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
67
68
  } else {
@@ -224,7 +225,8 @@ bool CallData::Prepare(const FunctionInfo *func, const Napi::CallbackInfo &info)
224
225
 
225
226
  *(void **)((param.fast ? fast_ptr : args_ptr)++) = ptr;
226
227
  } break;
227
- case PrimitiveKind::Record: {
228
+ case PrimitiveKind::Record:
229
+ case PrimitiveKind::Union: {
228
230
  if (RG_UNLIKELY(!IsObject(value))) {
229
231
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
230
232
  return false;
@@ -346,7 +348,8 @@ void CallData::Execute(const FunctionInfo *func)
346
348
  case PrimitiveKind::String:
347
349
  case PrimitiveKind::String16:
348
350
  case PrimitiveKind::Pointer:
349
- case PrimitiveKind::Record:
351
+ case PrimitiveKind::Record:
352
+ case PrimitiveKind::Union:
350
353
  case PrimitiveKind::Callback: { result.u64 = PERFORM_CALL(G); } break;
351
354
  case PrimitiveKind::Array: { RG_UNREACHABLE(); } break;
352
355
  case PrimitiveKind::Float32: { result.f = PERFORM_CALL(F); } break;
@@ -398,7 +401,8 @@ Napi::Value CallData::Complete(const FunctionInfo *func)
398
401
  return env.Null();
399
402
  }
400
403
  } break;
401
- case PrimitiveKind::Record: {
404
+ case PrimitiveKind::Record:
405
+ case PrimitiveKind::Union: {
402
406
  const uint8_t *ptr = return_ptr ? (const uint8_t *)return_ptr
403
407
  : (const uint8_t *)&result.buf;
404
408
 
@@ -617,7 +621,8 @@ void CallData::Relay(Size idx, uint8_t *, uint8_t *caller_sp, bool async, BackRe
617
621
  param.type->dispose(env, param.type, ptr2);
618
622
  }
619
623
  } break;
620
- case PrimitiveKind::Record: {
624
+ case PrimitiveKind::Record:
625
+ case PrimitiveKind::Union: {
621
626
  RG_ASSERT(!param.fast);
622
627
 
623
628
  uint8_t *ptr = (uint8_t *)args_ptr;
@@ -750,7 +755,8 @@ void CallData::Relay(Size idx, uint8_t *, uint8_t *caller_sp, bool async, BackRe
750
755
 
751
756
  if (CheckValueTag(instance, value, type->ref.marker)) {
752
757
  ptr = value.As<Napi::External<uint8_t>>().Data();
753
- } else if (IsObject(value) && type->ref.type->primitive == PrimitiveKind::Record) {
758
+ } else if (IsObject(value) && (type->ref.type->primitive == PrimitiveKind::Record ||
759
+ type->ref.type->primitive == PrimitiveKind::Union)) {
754
760
  Napi::Object obj = value.As<Napi::Object>();
755
761
 
756
762
  ptr = AllocHeap(type->ref.type->size, 16);
@@ -766,7 +772,8 @@ void CallData::Relay(Size idx, uint8_t *, uint8_t *caller_sp, bool async, BackRe
766
772
 
767
773
  out_reg->eax = (uint32_t)ptr;
768
774
  } break;
769
- case PrimitiveKind::Record: {
775
+ case PrimitiveKind::Record:
776
+ case PrimitiveKind::Union: {
770
777
  if (RG_UNLIKELY(!IsObject(value))) {
771
778
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
772
779
  return;