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
@@ -25,6 +25,11 @@
25
25
 
26
26
  namespace RG {
27
27
 
28
+ struct HfaInfo {
29
+ int count;
30
+ bool float32;
31
+ };
32
+
28
33
  struct X0X1Ret {
29
34
  uint64_t x0;
30
35
  uint64_t x1;
@@ -59,15 +64,61 @@ extern "C" napi_value CallSwitchStack(Napi::Function *func, size_t argc, napi_va
59
64
 
60
65
  #include "abi_trampolines.inc"
61
66
 
62
- static inline int IsHFA(const TypeInfo *type)
67
+ static HfaInfo IsHFA(const TypeInfo *type)
68
+ {
69
+ bool float32 = false;
70
+ bool float64 = false;
71
+ int count = 0;
72
+
73
+ count = AnalyseFlat(type, [&](const TypeInfo *type, int, int) {
74
+ if (type->primitive == PrimitiveKind::Float32) {
75
+ float32 = true;
76
+ } else if (type->primitive == PrimitiveKind::Float64) {
77
+ float64 = true;
78
+ } else {
79
+ float32 = true;
80
+ float64 = true;
81
+ }
82
+ });
83
+
84
+ HfaInfo info = {};
85
+
86
+ if (count < 1 || count > 4)
87
+ return info;
88
+ if (float32 && float64)
89
+ return info;
90
+
91
+ info.count = count;
92
+ info.float32 = float32;
93
+
94
+ return info;
95
+ }
96
+
97
+ static inline void ExpandFloats(uint8_t *ptr, Size len, Size bytes)
98
+ {
99
+ for (Size i = len - 1; i >= 0; i--) {
100
+ const uint8_t *src = ptr + i * bytes;
101
+ uint8_t *dest = ptr + i * 8;
102
+
103
+ memmove(dest, src, bytes);
104
+ }
105
+ }
106
+
107
+ static inline void CompactFloats(uint8_t *ptr, Size len, Size bytes)
63
108
  {
64
- return IsHFA(type, 1, 4);
109
+ for (Size i = 0; i < len; i++) {
110
+ const uint8_t *src = ptr + i * 8;
111
+ uint8_t *dest = ptr + i * bytes;
112
+
113
+ memmove(dest, src, bytes);
114
+ }
65
115
  }
66
116
 
67
117
  bool AnalyseFunction(Napi::Env, InstanceData *, FunctionInfo *func)
68
118
  {
69
- if (int hfa = IsHFA(func->ret.type); hfa) {
70
- func->ret.vec_count = (int8_t)hfa;
119
+ if (HfaInfo hfa = IsHFA(func->ret.type); hfa.count) {
120
+ func->ret.vec_count = (int8_t)hfa.count;
121
+ func->ret.vec_bytes = hfa.float32 ? 4 : 8;
71
122
  } else if (func->ret.type->size <= 16) {
72
123
  func->ret.gpr_count = (int8_t)((func->ret.type->size + 7) / 8);
73
124
  } else {
@@ -115,8 +166,9 @@ bool AnalyseFunction(Napi::Env, InstanceData *, FunctionInfo *func)
115
166
  gpr_avail--;
116
167
  }
117
168
  } break;
118
- case PrimitiveKind::Record: {
119
- int hfa = IsHFA(param.type);
169
+ case PrimitiveKind::Record:
170
+ case PrimitiveKind::Union: {
171
+ HfaInfo hfa = IsHFA(param.type);
120
172
 
121
173
  #ifdef _M_ARM64EC
122
174
  if (func->variadic) {
@@ -137,7 +189,7 @@ bool AnalyseFunction(Napi::Env, InstanceData *, FunctionInfo *func)
137
189
 
138
190
  #if defined(_WIN32)
139
191
  if (param.variadic) {
140
- hfa = 0;
192
+ hfa.count = 0;
141
193
  }
142
194
  #elif defined(__APPLE__)
143
195
  if (param.variadic) {
@@ -146,10 +198,11 @@ bool AnalyseFunction(Napi::Env, InstanceData *, FunctionInfo *func)
146
198
  }
147
199
  #endif
148
200
 
149
- if (hfa) {
150
- if (hfa <= vec_avail) {
151
- param.vec_count = (int8_t)hfa;
152
- vec_avail -= hfa;
201
+ if (hfa.count) {
202
+ if (hfa.count <= vec_avail) {
203
+ param.vec_count = (int8_t)hfa.count;
204
+ param.vec_bytes = hfa.float32 ? 4 : 8;
205
+ vec_avail -= hfa.count;
153
206
  } else {
154
207
  vec_avail = 0;
155
208
  }
@@ -364,7 +417,8 @@ bool CallData::Prepare(const FunctionInfo *func, const Napi::CallbackInfo &info)
364
417
  #endif
365
418
  *(void **)((param.gpr_count ? gpr_ptr : args_ptr)++) = ptr;
366
419
  } break;
367
- case PrimitiveKind::Record: {
420
+ case PrimitiveKind::Record:
421
+ case PrimitiveKind::Union: {
368
422
  if (RG_UNLIKELY(!IsObject(value))) {
369
423
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
370
424
  return false;
@@ -373,8 +427,12 @@ bool CallData::Prepare(const FunctionInfo *func, const Napi::CallbackInfo &info)
373
427
  Napi::Object obj = value.As<Napi::Object>();
374
428
 
375
429
  if (param.vec_count) { // HFA
376
- if (!PushObject(obj, param.type, (uint8_t *)vec_ptr, 8))
430
+ uint8_t *ptr = (uint8_t *)vec_ptr;
431
+
432
+ if (!PushObject(obj, param.type, ptr))
377
433
  return false;
434
+ ExpandFloats(ptr, param.vec_count, param.vec_bytes);
435
+
378
436
  vec_ptr += param.vec_count;
379
437
  } else if (!param.use_memory) {
380
438
  if (param.gpr_count) {
@@ -544,7 +602,8 @@ void CallData::Execute(const FunctionInfo *func)
544
602
  case PrimitiveKind::String16:
545
603
  case PrimitiveKind::Pointer:
546
604
  case PrimitiveKind::Callback: { result.u64 = PERFORM_CALL(GG).x0; } break;
547
- case PrimitiveKind::Record: {
605
+ case PrimitiveKind::Record:
606
+ case PrimitiveKind::Union: {
548
607
  if (func->ret.gpr_count) {
549
608
  X0X1Ret ret = PERFORM_CALL(GG);
550
609
  memcpy(&result.buf, &ret, RG_SIZE(ret));
@@ -605,9 +664,14 @@ Napi::Value CallData::Complete(const FunctionInfo *func)
605
664
  return env.Null();
606
665
  }
607
666
  } break;
608
- case PrimitiveKind::Record: {
667
+ case PrimitiveKind::Record:
668
+ case PrimitiveKind::Union: {
609
669
  if (func->ret.vec_count) { // HFA
610
- Napi::Object obj = DecodeObject(env, (const uint8_t *)&result.buf, func->ret.type, 8);
670
+ uint8_t *ptr = (uint8_t *)&result.buf;
671
+
672
+ CompactFloats(ptr, func->ret.vec_count, func->ret.vec_bytes);
673
+
674
+ Napi::Object obj = DecodeObject(env, ptr, func->ret.type);
611
675
  return obj;
612
676
  } else {
613
677
  const uint8_t *ptr = return_ptr ? (const uint8_t *)return_ptr
@@ -973,9 +1037,14 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, bool async,
973
1037
  param.type->dispose(env, param.type, ptr2);
974
1038
  }
975
1039
  } break;
976
- case PrimitiveKind::Record: {
1040
+ case PrimitiveKind::Record:
1041
+ case PrimitiveKind::Union: {
977
1042
  if (param.vec_count) { // HFA
978
- Napi::Object obj = DecodeObject(env, (uint8_t *)vec_ptr, param.type, 8);
1043
+ uint8_t *ptr = (uint8_t *)vec_ptr;
1044
+
1045
+ CompactFloats(ptr, param.vec_count, param.vec_bytes);
1046
+
1047
+ Napi::Object obj = DecodeObject(env, ptr, param.type);
979
1048
  arguments.Append(obj);
980
1049
 
981
1050
  vec_ptr += param.vec_count;
@@ -1133,7 +1202,8 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, bool async,
1133
1202
 
1134
1203
  if (CheckValueTag(instance, value, type->ref.marker)) {
1135
1204
  ptr = value.As<Napi::External<uint8_t>>().Data();
1136
- } else if (IsObject(value) && type->ref.type->primitive == PrimitiveKind::Record) {
1205
+ } else if (IsObject(value) && (type->ref.type->primitive == PrimitiveKind::Record ||
1206
+ type->ref.type->primitive == PrimitiveKind::Union)) {
1137
1207
  Napi::Object obj = value.As<Napi::Object>();
1138
1208
 
1139
1209
  ptr = AllocHeap(type->ref.type->size, 16);
@@ -1149,7 +1219,8 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, bool async,
1149
1219
 
1150
1220
  out_reg->x0 = (uint64_t)ptr;
1151
1221
  } break;
1152
- case PrimitiveKind::Record: {
1222
+ case PrimitiveKind::Record:
1223
+ case PrimitiveKind::Union: {
1153
1224
  if (RG_UNLIKELY(!IsObject(value))) {
1154
1225
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
1155
1226
  return;
@@ -1162,7 +1233,10 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, bool async,
1162
1233
  return;
1163
1234
  out_reg->x0 = (uint64_t)return_ptr;
1164
1235
  } else if (proto->ret.vec_count) { // HFA
1165
- PushObject(obj, type, (uint8_t *)&out_reg->d0, 8);
1236
+ uint8_t *ptr = (uint8_t *)&out_reg->d0;
1237
+
1238
+ ExpandFloats(ptr, proto->ret.vec_count, proto->ret.vec_bytes);
1239
+ PushObject(obj, type, ptr);
1166
1240
  } else {
1167
1241
  PushObject(obj, type, (uint8_t *)&out_reg->x0);
1168
1242
  }
@@ -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;