koffi 2.16.1 → 3.0.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/CHANGELOG.md +2 -2
  2. package/README.md +8 -8
  3. package/build/koffi/darwin_arm64/koffi.node +0 -0
  4. package/build/koffi/darwin_x64/koffi.node +0 -0
  5. package/build/koffi/freebsd_arm64/koffi.node +0 -0
  6. package/build/koffi/freebsd_ia32/koffi.node +0 -0
  7. package/build/koffi/freebsd_x64/koffi.node +0 -0
  8. package/build/koffi/linux_arm64/koffi.node +0 -0
  9. package/build/koffi/linux_ia32/koffi.node +0 -0
  10. package/build/koffi/linux_x64/koffi.node +0 -0
  11. package/build/koffi/musl_arm64/koffi.node +0 -0
  12. package/build/koffi/musl_x64/koffi.node +0 -0
  13. package/build/koffi/openbsd_ia32/koffi.node +0 -0
  14. package/build/koffi/openbsd_x64/koffi.node +0 -0
  15. package/build/koffi/win32_ia32/koffi.node +0 -0
  16. package/build/koffi/win32_x64/koffi.node +0 -0
  17. package/doc/benchmarks.md +33 -33
  18. package/doc/benchmarks.xlsx +0 -0
  19. package/doc/contribute.md +37 -25
  20. package/doc/index.md +8 -8
  21. package/doc/variables.md +1 -1
  22. package/index.d.ts +11 -9
  23. package/index.js +1 -634
  24. package/indirect.js +1 -533
  25. package/lib/native/base/base.cc +63 -85
  26. package/lib/native/base/base.hh +178 -151
  27. package/package.json +3 -4
  28. package/src/build.js +1178 -0
  29. package/src/koffi/CMakeLists.txt +97 -34
  30. package/src/koffi/index.js +359 -0
  31. package/src/koffi/indirect.js +216 -0
  32. package/src/koffi/src/{abi_arm32.cc → abi/arm32.cc} +279 -275
  33. package/src/koffi/src/{abi_arm32_asm.S → abi/arm32_asm.S} +2 -5
  34. package/src/koffi/src/abi/arm64.cc +1511 -0
  35. package/src/koffi/src/{abi_arm64_asm.S → abi/arm64_asm.S} +44 -23
  36. package/src/koffi/src/{abi_arm64_asm.asm → abi/arm64_asm.asm} +32 -25
  37. package/src/koffi/src/{abi_loong64_asm.S → abi/loong64_asm.S} +1 -5
  38. package/src/koffi/src/{abi_riscv64.cc → abi/riscv64.cc} +279 -273
  39. package/src/koffi/src/{abi_riscv64_asm.S → abi/riscv64_asm.S} +1 -4
  40. package/src/koffi/src/abi/x64sysv.cc +1456 -0
  41. package/src/koffi/src/{abi_x64_sysv_asm.S → abi/x64sysv_asm.S} +30 -33
  42. package/src/koffi/src/abi/x64win.cc +1121 -0
  43. package/src/koffi/src/{abi_x64_win_asm.S → abi/x64win_asm.S} +8 -12
  44. package/src/koffi/src/{abi_x64_win_asm.asm → abi/x64win_asm.asm} +11 -14
  45. package/src/koffi/src/abi/x86.cc +1233 -0
  46. package/src/koffi/src/{abi_x86_asm.S → abi/x86_asm.S} +49 -25
  47. package/src/koffi/src/{abi_x86_asm.asm → abi/x86_asm.asm} +11 -14
  48. package/src/koffi/src/call.cc +458 -598
  49. package/src/koffi/src/call.hh +61 -82
  50. package/src/koffi/src/ffi.cc +595 -309
  51. package/src/koffi/src/ffi.hh +103 -89
  52. package/src/koffi/src/parser.cc +0 -4
  53. package/src/koffi/src/primitives.inc +39 -0
  54. package/src/koffi/{tools/write_trampolines.js → src/trampolines.js} +1 -1
  55. package/src/koffi/src/util.cc +503 -446
  56. package/src/koffi/src/util.hh +269 -57
  57. package/src/koffi/src/uv.cc +2 -2
  58. package/src/koffi/src/uv.def +3 -0
  59. package/src/koffi/src/win32.hh +30 -1
  60. package/vendor/node-addon-api/napi-inl.h +4 -0
  61. package/vendor/node-addon-api/napi.h +1 -0
  62. package/build/koffi/linux_armhf/koffi.node +0 -0
  63. package/build/koffi/linux_loong64/koffi.node +0 -0
  64. package/build/koffi/linux_riscv64d/koffi.node +0 -0
  65. package/build/koffi/win32_arm64/koffi.exp +0 -0
  66. package/build/koffi/win32_arm64/koffi.lib +0 -0
  67. package/build/koffi/win32_arm64/koffi.node +0 -0
  68. package/doc/platforms.md +0 -36
  69. package/src/cnoke/LICENSE.txt +0 -22
  70. package/src/cnoke/README.md +0 -99
  71. package/src/cnoke/assets/FindCNoke.cmake +0 -127
  72. package/src/cnoke/assets/toolchains.json +0 -126
  73. package/src/cnoke/assets/win_delay_hook.c +0 -36
  74. package/src/cnoke/cnoke.js +0 -170
  75. package/src/cnoke/package.json +0 -24
  76. package/src/cnoke/src/builder.js +0 -511
  77. package/src/cnoke/src/index.js +0 -10
  78. package/src/cnoke/src/tools.js +0 -407
  79. package/src/koffi/src/abi_arm64.cc +0 -1295
  80. package/src/koffi/src/abi_x64_sysv.cc +0 -939
  81. package/src/koffi/src/abi_x64_win.cc +0 -715
  82. package/src/koffi/src/abi_x86.cc +0 -860
  83. package/src/koffi/src/init.js +0 -105
  84. /package/src/koffi/src/{abi_loong64.cc → abi/loong64.cc} +0 -0
@@ -0,0 +1,1511 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // SPDX-FileCopyrightText: 2025 Niels Martignène <niels.martignene@protonmail.com>
3
+
4
+ #if defined(__aarch64__) || defined(_M_ARM64)
5
+
6
+ #include "lib/native/base/base.hh"
7
+ #include "../ffi.hh"
8
+ #include "../call.hh"
9
+ #include "../util.hh"
10
+ #if defined(_WIN32)
11
+ #include "../win32.hh"
12
+ #endif
13
+
14
+ #include <napi.h>
15
+
16
+ namespace K {
17
+
18
+ struct HfaInfo {
19
+ int count;
20
+ bool float32;
21
+ };
22
+
23
+ struct X0X1Ret {
24
+ uint64_t x0;
25
+ uint64_t x1;
26
+ };
27
+ struct HfaRet {
28
+ double d0;
29
+ double d1;
30
+ double d2;
31
+ double d3;
32
+ };
33
+
34
+ struct BackRegisters {
35
+ uint64_t x0;
36
+ uint64_t x1;
37
+
38
+ double d0;
39
+ double d1;
40
+ double d2;
41
+ double d3;
42
+ };
43
+
44
+ extern "C" X0X1Ret ForwardCallGG(const void *func, uint8_t *sp, uint8_t **out_saved_sp);
45
+ extern "C" float ForwardCallF(const void *func, uint8_t *sp, uint8_t **out_saved_sp);
46
+ extern "C" HfaRet ForwardCallDDDD(const void *func, uint8_t *sp, uint8_t **out_saved_sp);
47
+
48
+ extern "C" X0X1Ret ForwardCallGGX(const void *func, uint8_t *sp, uint8_t **out_saved_sp);
49
+ extern "C" float ForwardCallFX(const void *func, uint8_t *sp, uint8_t **out_saved_sp);
50
+ extern "C" HfaRet ForwardCallDDDDX(const void *func, uint8_t *sp, uint8_t **out_saved_sp);
51
+
52
+ enum class AbiOpcode {
53
+ #define PRIMITIVE(Name) Push ## Name,
54
+ #include "../primitives.inc"
55
+ PushAggregateReg,
56
+ PushAggregateStack,
57
+ PushHfa32,
58
+ #define PRIMITIVE(Name) Run ## Name,
59
+ #include "../primitives.inc"
60
+ RunAggregateGG,
61
+ RunAggregateDDDD,
62
+ RunHfa32,
63
+ RunAggregateStack,
64
+ #define PRIMITIVE(Name) Run ## Name ## X,
65
+ #include "../primitives.inc"
66
+ RunAggregateGGX,
67
+ RunAggregateDDDDX,
68
+ RunHfa32X,
69
+ RunAggregateStackX,
70
+ Yield,
71
+ CallGG,
72
+ CallF,
73
+ CallDDDD,
74
+ CallStack,
75
+ CallGGX,
76
+ CallFX,
77
+ CallDDDDX,
78
+ CallStackX,
79
+ #define PRIMITIVE(Name) Return ## Name,
80
+ #include "../primitives.inc"
81
+ ReturnAggregateReg,
82
+ ReturnAggregateStack,
83
+ ReturnHfa32,
84
+ #if defined(_M_ARM64EC)
85
+ SetVariadicRegisters
86
+ #endif
87
+ };
88
+
89
+ namespace {
90
+ #if defined(MUST_TAIL)
91
+ PRESERVE_NONE typedef napi_value ForwardFunc(CallData *call, napi_value *args, uint8_t *base, const AbiInstruction *inst);
92
+
93
+ extern ForwardFunc *const ForwardDispatch[256];
94
+
95
+ inline void *Code2Op(AbiOpcode code)
96
+ {
97
+ return (void *)ForwardDispatch[(int)code];
98
+ }
99
+ #else
100
+ inline void *Code2Op(AbiOpcode code)
101
+ {
102
+ return (void *)code;
103
+ }
104
+ #endif
105
+ }
106
+
107
+ static HfaInfo IsHFA(const TypeInfo *type)
108
+ {
109
+ bool float32 = false;
110
+ bool float64 = false;
111
+ int count = 0;
112
+
113
+ count = AnalyseFlat(type, [&](const TypeInfo *type, int, int) {
114
+ if (type->primitive == PrimitiveKind::Float32) {
115
+ float32 = true;
116
+ } else if (type->primitive == PrimitiveKind::Float64) {
117
+ float64 = true;
118
+ } else {
119
+ float32 = true;
120
+ float64 = true;
121
+ }
122
+ });
123
+
124
+ HfaInfo info = {};
125
+
126
+ if (count < 1 || count > 4)
127
+ return info;
128
+ if (float32 && float64)
129
+ return info;
130
+
131
+ info.count = count;
132
+ info.float32 = float32;
133
+
134
+ return info;
135
+ }
136
+
137
+ bool AnalyseFunction(Napi::Env, InstanceData *, FunctionInfo *func)
138
+ {
139
+ Size gpr_index = 0;
140
+ Size vec_index = 0;
141
+ Size stack_offset = 0;
142
+
143
+ #if defined(_M_ARM64EC)
144
+ int gpr_max = func->variadic ? 4 : 8;
145
+ int vec_max = 8;
146
+ #else
147
+ int gpr_max = 8;
148
+ int vec_max = 8;
149
+ #endif
150
+
151
+ for (ParameterInfo &param: func->parameters) {
152
+ #if defined(__APPLE__)
153
+ if (param.variadic) {
154
+ gpr_index = gpr_max;
155
+ vec_index = vec_max;
156
+ }
157
+ #endif
158
+
159
+ switch (param.type->primitive) {
160
+ case PrimitiveKind::Void: { K_UNREACHABLE(); } break;
161
+
162
+ case PrimitiveKind::Bool:
163
+ case PrimitiveKind::Int8:
164
+ case PrimitiveKind::UInt8:
165
+ case PrimitiveKind::Int16:
166
+ case PrimitiveKind::Int16S:
167
+ case PrimitiveKind::UInt16:
168
+ case PrimitiveKind::UInt16S:
169
+ case PrimitiveKind::Int32:
170
+ case PrimitiveKind::Int32S:
171
+ case PrimitiveKind::UInt32:
172
+ case PrimitiveKind::UInt32S:
173
+ case PrimitiveKind::Int64:
174
+ case PrimitiveKind::Int64S:
175
+ case PrimitiveKind::UInt64:
176
+ case PrimitiveKind::UInt64S:
177
+ case PrimitiveKind::String:
178
+ case PrimitiveKind::String16:
179
+ case PrimitiveKind::String32:
180
+ case PrimitiveKind::Pointer:
181
+ case PrimitiveKind::Callback: {
182
+ if (gpr_index < gpr_max) {
183
+ param.abi.regular = true;
184
+ param.abi.offset = gpr_index * 8;
185
+ gpr_index++;
186
+ } else {
187
+ #if defined(__APPLE__)
188
+ stack_offset = AlignLen(stack_offset, param.variadic ? 8 : param.type->align);
189
+ param.abi.offset = 19 * 8 + stack_offset;
190
+ stack_offset += param.type->size;
191
+ #else
192
+ param.abi.offset = 19 * 8 + stack_offset;
193
+ stack_offset += 8;
194
+ #endif
195
+ }
196
+
197
+ int delta = (int)AbiOpcode::PushVoid - (int)PrimitiveKind::Void;
198
+ AbiOpcode code = (AbiOpcode)((int)param.type->primitive + delta);
199
+
200
+ func->sync.Append({ .op = Code2Op(code), .a = param.offset, .b1 = (int16_t)param.abi.offset, .b2 = (int16_t)param.directions, .type = param.type });
201
+ func->async.Append({ .op = Code2Op(code), .a = param.offset, .b1 = (int16_t)param.abi.offset, .b2 = (int16_t)param.directions, .type = param.type });
202
+ } break;
203
+
204
+ case PrimitiveKind::Record:
205
+ case PrimitiveKind::Union: {
206
+ #if defined(_M_ARM64EC)
207
+ if (func->variadic) {
208
+ if (IsRegularSize(param.type->size, 8) && gpr_index < gpr_max) {
209
+ param.abi.regular = true;
210
+ param.abi.offset = gpr_index;
211
+ gpr_index++;
212
+
213
+ func->sync.Append({ .op = Code2Op(AbiOpcode::PushAggregateReg), .a = param.offset, .b1 = (int16_t)param.abi.offset, .type = param.type });
214
+ func->async.Append({ .op = Code2Op(AbiOpcode::PushAggregateReg), .a = param.offset, .b1 = (int16_t)param.abi.offset, .type = param.type });
215
+ } else {
216
+ if (gpr_index < gpr_max) {
217
+ param.abi.regular = true;
218
+ param.abi.offset = gpr_index * 8;
219
+ gpr_index++;
220
+ } else {
221
+ param.abi.offset = 19 * 8 + stack_offset;
222
+ stack_offset += 8;
223
+ }
224
+
225
+ param.abi.indirect = true;
226
+
227
+ func->sync.Append({ .op = Code2Op(AbiOpcode::PushAggregateStack), .a = param.offset, .b1 = (int16_t)param.abi.offset, .type = param.type });
228
+ func->async.Append({ .op = Code2Op(AbiOpcode::PushAggregateStack), .a = param.offset, .b1 = (int16_t)param.abi.offset, .type = param.type });
229
+ }
230
+
231
+ break;
232
+ }
233
+ #endif
234
+
235
+ #if defined(__APPLE__)
236
+ if (param.variadic) {
237
+ if (param.type->size <= 16) {
238
+ int registers = (param.type->size + 7) / 8;
239
+
240
+ if (registers <= gpr_max - gpr_index) {
241
+ K_ASSERT(param.type->align <= 8);
242
+
243
+ param.abi.regular = true;
244
+ param.abi.offset = gpr_index * 8;
245
+ gpr_index += registers;
246
+ } else {
247
+ gpr_index = gpr_max;
248
+
249
+ stack_offset = AlignLen(stack_offset, param.type->align);
250
+ param.abi.offset = 19 * 8 + stack_offset;
251
+ stack_offset += registers * 8;
252
+ }
253
+
254
+ func->sync.Append({ .op = Code2Op(AbiOpcode::PushAggregateReg), .a = param.offset, .b1 = (int16_t)param.abi.offset, .type = param.type });
255
+ func->async.Append({ .op = Code2Op(AbiOpcode::PushAggregateReg), .a = param.offset, .b1 = (int16_t)param.abi.offset, .type = param.type });
256
+ } else {
257
+ if (gpr_index < gpr_max) {
258
+ param.abi.regular = true;
259
+ param.abi.offset = gpr_index * 8;
260
+ gpr_index++;
261
+ } else {
262
+ stack_offset = AlignLen(stack_offset, 8);
263
+ param.abi.offset = 19 * 8 + stack_offset;
264
+ stack_offset += 8;
265
+ }
266
+
267
+ param.abi.indirect = true;
268
+
269
+ func->sync.Append({ .op = Code2Op(AbiOpcode::PushAggregateStack), .a = param.offset, .b1 = (int16_t)param.abi.offset, .type = param.type });
270
+ func->async.Append({ .op = Code2Op(AbiOpcode::PushAggregateStack), .a = param.offset, .b1 = (int16_t)param.abi.offset, .type = param.type });
271
+ }
272
+
273
+ break;
274
+ }
275
+ #endif
276
+
277
+ HfaInfo hfa = IsHFA(param.type);
278
+
279
+ if (param.variadic) {
280
+ // Windows ignores HFA optimization for variadic parameters
281
+ hfa.count = 0;
282
+ }
283
+
284
+ if (hfa.count) {
285
+ if (hfa.count <= vec_max - vec_index) {
286
+ param.abi.regular = true;
287
+ param.abi.offset = 9 * 8 + vec_index * 8;
288
+ vec_index += hfa.count;
289
+
290
+ if (hfa.float32) {
291
+ param.abi.hfa32 = hfa.count;
292
+
293
+ func->sync.Append({ .op = Code2Op(AbiOpcode::PushHfa32), .a = param.offset, .b1 = (int16_t)param.abi.offset, .b2 = (int16_t)hfa.count, .type = param.type });
294
+ func->async.Append({ .op = Code2Op(AbiOpcode::PushHfa32), .a = param.offset, .b1 = (int16_t)param.abi.offset, .b2 = (int16_t)hfa.count, .type = param.type });
295
+ } else {
296
+ func->sync.Append({ .op = Code2Op(AbiOpcode::PushAggregateReg), .a = param.offset, .b1 = (int16_t)param.abi.offset, .type = param.type });
297
+ func->async.Append({ .op = Code2Op(AbiOpcode::PushAggregateReg), .a = param.offset, .b1 = (int16_t)param.abi.offset, .type = param.type });
298
+ }
299
+ } else {
300
+ vec_index = vec_max;
301
+
302
+ #if defined(__APPLE__)
303
+ stack_offset = AlignLen(stack_offset, param.type->align);
304
+ #endif
305
+ param.abi.offset = 19 * 8 + stack_offset;
306
+ stack_offset += 8;
307
+
308
+ func->sync.Append({ .op = Code2Op(AbiOpcode::PushAggregateReg), .a = param.offset, .b1 = (int16_t)param.abi.offset, .type = param.type });
309
+ func->async.Append({ .op = Code2Op(AbiOpcode::PushAggregateReg), .a = param.offset, .b1 = (int16_t)param.abi.offset, .type = param.type });
310
+ }
311
+ } else if (param.type->size <= 16) {
312
+ int registers = (param.type->size + 7) / 8;
313
+
314
+ if (registers <= gpr_max - gpr_index) {
315
+ K_ASSERT(param.type->align <= 8);
316
+
317
+ param.abi.regular = true;
318
+ param.abi.offset = gpr_index * 8;
319
+ gpr_index += registers;
320
+ } else {
321
+ gpr_index = gpr_max;
322
+
323
+ #if defined(__APPLE__)
324
+ stack_offset = AlignLen(stack_offset, 8);
325
+ #endif
326
+ param.abi.offset = 19 * 8 + stack_offset;
327
+ stack_offset += registers * 8;
328
+ }
329
+
330
+ func->sync.Append({ .op = Code2Op(AbiOpcode::PushAggregateReg), .a = param.offset, .b1 = (int16_t)param.abi.offset, .type = param.type });
331
+ func->async.Append({ .op = Code2Op(AbiOpcode::PushAggregateReg), .a = param.offset, .b1 = (int16_t)param.abi.offset, .type = param.type });
332
+ } else {
333
+ // Big types (more than 16 bytes) are replaced by a pointer
334
+ if (gpr_index < gpr_max) {
335
+ param.abi.regular = true;
336
+ param.abi.offset = gpr_index * 8;
337
+ gpr_index++;
338
+ } else {
339
+ #if defined(__APPLE__)
340
+ stack_offset = AlignLen(stack_offset, 8);
341
+ #endif
342
+ param.abi.offset = 19 * 8 + stack_offset;
343
+ stack_offset += 8;
344
+ }
345
+
346
+ param.abi.indirect = true;
347
+
348
+ func->sync.Append({ .op = Code2Op(AbiOpcode::PushAggregateStack), .a = param.offset, .b1 = (int16_t)param.abi.offset, .type = param.type });
349
+ func->async.Append({ .op = Code2Op(AbiOpcode::PushAggregateStack), .a = param.offset, .b1 = (int16_t)param.abi.offset, .type = param.type });
350
+ }
351
+ } break;
352
+ case PrimitiveKind::Array: { K_UNREACHABLE(); } break;
353
+
354
+ case PrimitiveKind::Float32: {
355
+ #if defined(_WIN32)
356
+ if (param.variadic) {
357
+ if (gpr_index < gpr_max) {
358
+ param.abi.regular = true;
359
+ param.abi.offset = gpr_index * 8;
360
+ gpr_index++;
361
+ } else {
362
+ param.abi.offset = 19 * 8 + stack_offset;
363
+ stack_offset += 8;
364
+ }
365
+
366
+ func->sync.Append({ .op = Code2Op(AbiOpcode::PushFloat32), .a = param.offset, .b1 = (int16_t)param.abi.offset, .b2 = (int16_t)param.directions, .type = param.type });
367
+ func->async.Append({ .op = Code2Op(AbiOpcode::PushFloat32), .a = param.offset, .b1 = (int16_t)param.abi.offset, .b2 = (int16_t)param.directions, .type = param.type });
368
+
369
+ break;
370
+ }
371
+ #endif
372
+
373
+ if (vec_index < vec_max) {
374
+ param.abi.regular = true;
375
+ param.abi.offset = 9 * 8 + vec_index * 8;
376
+ vec_index++;
377
+ } else {
378
+ #if defined(__APPLE__)
379
+ stack_offset = AlignLen(stack_offset, param.variadic ? 8 : 4);
380
+ param.abi.offset = 19 * 8 + stack_offset;
381
+ stack_offset += 4;
382
+ #else
383
+ param.abi.offset = 19 * 8 + stack_offset;
384
+ stack_offset += 8;
385
+ #endif
386
+ }
387
+
388
+ func->sync.Append({ .op = Code2Op(AbiOpcode::PushFloat32), .a = param.offset, .b1 = (int16_t)param.abi.offset, .b2 = (int16_t)param.directions, .type = param.type });
389
+ func->async.Append({ .op = Code2Op(AbiOpcode::PushFloat32), .a = param.offset, .b1 = (int16_t)param.abi.offset, .b2 = (int16_t)param.directions, .type = param.type });
390
+ } break;
391
+ case PrimitiveKind::Float64: {
392
+ #if defined(_WIN32)
393
+ if (param.variadic) {
394
+ if (gpr_index < gpr_max) {
395
+ param.abi.regular = true;
396
+ param.abi.offset = gpr_index * 8;
397
+ gpr_index++;
398
+ } else {
399
+ param.abi.offset = 19 * 8 + stack_offset;
400
+ stack_offset += 8;
401
+ }
402
+
403
+ func->sync.Append({ .op = Code2Op(AbiOpcode::PushFloat64), .a = param.offset, .b1 = (int16_t)param.abi.offset, .b2 = (int16_t)param.directions, .type = param.type });
404
+ func->async.Append({ .op = Code2Op(AbiOpcode::PushFloat64), .a = param.offset, .b1 = (int16_t)param.abi.offset, .b2 = (int16_t)param.directions, .type = param.type });
405
+
406
+ break;
407
+ }
408
+ #endif
409
+
410
+ if (vec_index < vec_max) {
411
+ param.abi.regular = true;
412
+ param.abi.offset = 9 * 8 + vec_index * 8;
413
+ vec_index++;
414
+ } else {
415
+ #if defined(__APPLE__)
416
+ stack_offset = AlignLen(stack_offset, 8);
417
+ #endif
418
+ param.abi.offset = 19 * 8 + stack_offset;
419
+ stack_offset += 8;
420
+ }
421
+
422
+ func->sync.Append({ .op = Code2Op(AbiOpcode::PushFloat64), .a = param.offset, .b1 = (int16_t)param.abi.offset, .b2 = (int16_t)param.directions, .type = param.type });
423
+ func->async.Append({ .op = Code2Op(AbiOpcode::PushFloat64), .a = param.offset, .b1 = (int16_t)param.abi.offset, .b2 = (int16_t)param.directions, .type = param.type });
424
+ } break;
425
+
426
+ case PrimitiveKind::Prototype: { K_UNREACHABLE(); } break;
427
+ }
428
+ }
429
+
430
+ func->stk_size = AlignLen(19 * 8 + stack_offset, 16) + 8;
431
+ func->forward_fp = vec_index;
432
+
433
+ func->async.Append({ .op = Code2Op(AbiOpcode::Yield) });
434
+
435
+ #if defined(_M_ARM64EC)
436
+ if (func->variadic) {
437
+ func->sync.Append({ .op = Code2Op(AbiOpcode::SetVariadicRegisters), .a = (int32_t)stack_offset });
438
+ func->async.Append({ .op = Code2Op(AbiOpcode::SetVariadicRegisters), .a = (int32_t)stack_offset });
439
+ }
440
+ #endif
441
+
442
+ switch (func->ret.type->primitive) {
443
+ case PrimitiveKind::Void:
444
+ case PrimitiveKind::Bool:
445
+ case PrimitiveKind::Int8:
446
+ case PrimitiveKind::UInt8:
447
+ case PrimitiveKind::Int16:
448
+ case PrimitiveKind::Int16S:
449
+ case PrimitiveKind::UInt16:
450
+ case PrimitiveKind::UInt16S:
451
+ case PrimitiveKind::Int32:
452
+ case PrimitiveKind::Int32S:
453
+ case PrimitiveKind::UInt32:
454
+ case PrimitiveKind::UInt32S:
455
+ case PrimitiveKind::Int64:
456
+ case PrimitiveKind::Int64S:
457
+ case PrimitiveKind::UInt64:
458
+ case PrimitiveKind::UInt64S:
459
+ case PrimitiveKind::String:
460
+ case PrimitiveKind::String16:
461
+ case PrimitiveKind::String32:
462
+ case PrimitiveKind::Pointer:
463
+ case PrimitiveKind::Callback: {
464
+ if (func->forward_fp) {
465
+ int delta = (int)AbiOpcode::RunVoidX - (int)PrimitiveKind::Void;
466
+ AbiOpcode run = (AbiOpcode)((int)func->ret.type->primitive + delta);
467
+
468
+ func->sync.Append({ .op = Code2Op(run), .type = func->ret.type });
469
+ } else {
470
+ int delta = (int)AbiOpcode::RunVoid - (int)PrimitiveKind::Void;
471
+ AbiOpcode run = (AbiOpcode)((int)func->ret.type->primitive + delta);
472
+
473
+ func->sync.Append({ .op = Code2Op(run), .type = func->ret.type });
474
+ }
475
+
476
+ // Async
477
+ {
478
+ int delta = (int)AbiOpcode::ReturnVoid - (int)PrimitiveKind::Void;
479
+ AbiOpcode call = func->forward_fp ? AbiOpcode::CallGGX : AbiOpcode::CallGG;
480
+ AbiOpcode ret = (AbiOpcode)((int)func->ret.type->primitive + delta);
481
+
482
+ func->async.Append({ .op = Code2Op(call) });
483
+ func->async.Append({ .op = Code2Op(ret), .type = func->ret.type });
484
+ }
485
+ } break;
486
+
487
+ case PrimitiveKind::Record:
488
+ case PrimitiveKind::Union: {
489
+ HfaInfo hfa = IsHFA(func->ret.type);
490
+
491
+ if (hfa.count && hfa.float32) {
492
+ func->ret.abi.regular = true;
493
+ func->ret.abi.offset = offsetof(BackRegisters, d0);
494
+ func->ret.abi.hfa32 = hfa.count;
495
+
496
+ AbiOpcode run = func->forward_fp ? AbiOpcode::RunHfa32X : AbiOpcode::RunHfa32;
497
+ AbiOpcode call = func->forward_fp ? AbiOpcode::CallDDDDX : AbiOpcode::CallDDDD;
498
+
499
+ func->sync.Append({ .op = Code2Op(run), .a = hfa.count, .type = func->ret.type });
500
+ func->async.Append({ .op = Code2Op(call) });
501
+ func->async.Append({ .op = Code2Op(AbiOpcode::ReturnHfa32), .a = hfa.count, .type = func->ret.type });
502
+ } else if (hfa.count) {
503
+ func->ret.abi.regular = true;
504
+ func->ret.abi.offset = offsetof(BackRegisters, d0);
505
+
506
+ AbiOpcode run = func->forward_fp ? AbiOpcode::RunAggregateDDDDX : AbiOpcode::RunAggregateDDDD;
507
+ AbiOpcode call = func->forward_fp ? AbiOpcode::CallDDDDX : AbiOpcode::CallDDDD;
508
+
509
+ func->sync.Append({ .op = Code2Op(run), .type = func->ret.type });
510
+ func->async.Append({ .op = Code2Op(call) });
511
+ func->async.Append({ .op = Code2Op(AbiOpcode::ReturnAggregateReg), .type = func->ret.type });
512
+ } else if (func->ret.type->size <= 16) {
513
+ func->ret.abi.regular = true;
514
+ func->ret.abi.offset = offsetof(BackRegisters, x0);
515
+
516
+ AbiOpcode run = func->forward_fp ? AbiOpcode::RunAggregateGGX : AbiOpcode::RunAggregateGG;
517
+ AbiOpcode call = func->forward_fp ? AbiOpcode::CallGGX : AbiOpcode::CallGG;
518
+
519
+ func->sync.Append({ .op = Code2Op(run), .type = func->ret.type });
520
+ func->async.Append({ .op = Code2Op(call) });
521
+ func->async.Append({ .op = Code2Op(AbiOpcode::ReturnAggregateReg), .type = func->ret.type });
522
+ } else {
523
+ AbiOpcode run = func->forward_fp ? AbiOpcode::RunAggregateStackX : AbiOpcode::RunAggregateStack;
524
+ AbiOpcode call = func->forward_fp ? AbiOpcode::CallStackX : AbiOpcode::CallStack;
525
+
526
+ func->sync.Append({ .op = Code2Op(run), .a = (int32_t)func->ret.type->size, .type = func->ret.type });
527
+ func->async.Append({ .op = Code2Op(call), .a = (int32_t)func->ret.type->size });
528
+ func->async.Append({ .op = Code2Op(AbiOpcode::ReturnAggregateStack), .type = func->ret.type });
529
+ }
530
+ } break;
531
+ case PrimitiveKind::Array: { K_UNREACHABLE(); } break;
532
+
533
+ case PrimitiveKind::Float32: {
534
+ AbiOpcode run = func->forward_fp ? AbiOpcode::RunFloat32X : AbiOpcode::RunFloat32;
535
+ AbiOpcode call = func->forward_fp ? AbiOpcode::CallFX : AbiOpcode::CallF;
536
+
537
+ func->sync.Append({ .op = Code2Op(run), .type = func->ret.type });
538
+ func->async.Append({ .op = Code2Op(call) });
539
+ func->async.Append({ .op = Code2Op(AbiOpcode::ReturnFloat32), .type = func->ret.type });
540
+ } break;
541
+ case PrimitiveKind::Float64: {
542
+ AbiOpcode run = func->forward_fp ? AbiOpcode::RunFloat64X : AbiOpcode::RunFloat64;
543
+ AbiOpcode call = func->forward_fp ? AbiOpcode::CallDDDDX : AbiOpcode::CallDDDD;
544
+
545
+ func->sync.Append({ .op = Code2Op(run), .type = func->ret.type });
546
+ func->async.Append({ .op = Code2Op(call) });
547
+ func->async.Append({ .op = Code2Op(AbiOpcode::ReturnFloat64), .type = func->ret.type });
548
+ } break;
549
+
550
+ case PrimitiveKind::Prototype: { K_UNREACHABLE(); } break;
551
+ }
552
+
553
+ return true;
554
+ }
555
+
556
+ static inline void ExpandFloats(uint8_t *ptr, Size len)
557
+ {
558
+ for (Size i = len - 1; i >= 0; i--) {
559
+ const uint8_t *src = ptr + i * 4;
560
+ uint8_t *dest = ptr + i * 8;
561
+
562
+ memmove(dest, src, 4);
563
+ }
564
+ }
565
+
566
+ static inline void CompactFloats(uint8_t *ptr, Size len)
567
+ {
568
+ for (Size i = 0; i < len; i++) {
569
+ const uint8_t *src = ptr + i * 8;
570
+ uint8_t *dest = ptr + i * 4;
571
+
572
+ memmove(dest, src, 4);
573
+ }
574
+ }
575
+
576
+ #pragma GCC diagnostic push
577
+ #pragma GCC diagnostic ignored "-Wunused-parameter"
578
+
579
+ namespace {
580
+ #if defined(MUST_TAIL)
581
+ #define OP(Code) \
582
+ PRESERVE_NONE napi_value Handle ## Code(CallData *call, napi_value *args, uint8_t *base, const AbiInstruction *inst)
583
+ #define NEXT() \
584
+ do { \
585
+ const AbiInstruction *next = inst + 1; \
586
+ MUST_TAIL return ((ForwardFunc *)next->op)(call, args, base, next); \
587
+ } while (false)
588
+ #else
589
+ #define OP(Code) \
590
+ case (int)AbiOpcode::Code:
591
+ #define NEXT() \
592
+ break
593
+
594
+ napi_value RunLoop(CallData *call, napi_value *args, uint8_t *base, const AbiInstruction *inst)
595
+ {
596
+ for (;; ++inst) {
597
+ switch ((intptr_t)inst->op) {
598
+ #endif
599
+
600
+ #if defined(_WIN32)
601
+ #define WRAP(Expr) \
602
+ [&]() { \
603
+ TEB *teb = GetTEB(); \
604
+ \
605
+ ADJUST_TEB(teb, call->mem->stack0.ptr, call->mem->stack0.end); \
606
+ \
607
+ return (Expr); \
608
+ }()
609
+ #else
610
+ #define WRAP(Expr) (Expr)
611
+ #endif
612
+
613
+ #define INTEGER(CType) \
614
+ do { \
615
+ CType v; \
616
+ if (!TryNumber(call->env, args[inst->a], &v)) [[unlikely]] { \
617
+ ThrowError<Napi::TypeError>(call->env, "Unexpected %1 value, expected number", GetValueType(call->instance, args[inst->a])); \
618
+ return call->env.Null(); \
619
+ } \
620
+ \
621
+ *(uint64_t *)(base + inst->b1) = (uint64_t)v; \
622
+ } while (false)
623
+ #define INTEGER_SWAP(CType) \
624
+ do { \
625
+ CType v; \
626
+ if (!TryNumber(call->env, args[inst->a], &v)) [[unlikely]] { \
627
+ ThrowError<Napi::TypeError>(call->env, "Unexpected %1 value, expected number", GetValueType(call->instance, args[inst->a])); \
628
+ return call->env.Null(); \
629
+ } \
630
+ \
631
+ *(uint64_t *)(base + inst->b1) = (uint64_t)ReverseBytes(v); \
632
+ } while (false)
633
+
634
+ OP(PushVoid) { K_UNREACHABLE(); return call->env.Null(); }
635
+ OP(PushBool) {
636
+ bool b;
637
+ if (napi_get_value_bool(call->env, args[inst->a], &b) != napi_ok) [[unlikely]] {
638
+ ThrowError<Napi::TypeError>(call->env, "Unexpected %1 value, expected boolean", GetValueType(call->instance, args[inst->a]));
639
+ return call->env.Null();
640
+ }
641
+
642
+ *(uint64_t *)(base + inst->b1) = (uint64_t)b;
643
+
644
+ NEXT();
645
+ }
646
+ OP(PushInt8) { INTEGER(int8_t); NEXT(); }
647
+ OP(PushUInt8) { INTEGER(uint8_t); NEXT(); }
648
+ OP(PushInt16) { INTEGER(int16_t); NEXT(); }
649
+ OP(PushInt16S) { INTEGER_SWAP(int16_t); NEXT(); }
650
+ OP(PushUInt16) { INTEGER(uint16_t); NEXT(); }
651
+ OP(PushUInt16S) { INTEGER_SWAP(uint16_t); NEXT(); }
652
+ OP(PushInt32) { INTEGER(int32_t); NEXT(); }
653
+ OP(PushInt32S) { INTEGER_SWAP(int32_t); NEXT(); }
654
+ OP(PushUInt32) { INTEGER(uint32_t); NEXT(); }
655
+ OP(PushUInt32S) { INTEGER_SWAP(uint32_t); NEXT(); }
656
+ OP(PushInt64) { INTEGER(int64_t); NEXT(); }
657
+ OP(PushInt64S) { INTEGER_SWAP(int64_t); NEXT(); }
658
+ OP(PushUInt64) { INTEGER(int64_t); NEXT(); }
659
+ OP(PushUInt64S) { INTEGER_SWAP(int64_t); NEXT(); }
660
+ OP(PushString) {
661
+ const char *str;
662
+ if (!call->PushString(args[inst->a], inst->b2, &str)) [[unlikely]]
663
+ return call->env.Null();
664
+
665
+ *(const char **)(base + inst->b1) = str;
666
+
667
+ NEXT();
668
+ }
669
+ OP(PushString16) {
670
+ const char16_t *str16;
671
+ if (!call->PushString16(args[inst->a], inst->b2, &str16)) [[unlikely]]
672
+ return call->env.Null();
673
+
674
+ *(const char16_t **)(base + inst->b1) = str16;
675
+
676
+ NEXT();
677
+ }
678
+ OP(PushString32) {
679
+ const char32_t *str32;
680
+ if (!call->PushString32(args[inst->a], inst->b2, &str32)) [[unlikely]]
681
+ return call->env.Null();
682
+
683
+ *(const char32_t **)(base + inst->b1) = str32;
684
+
685
+ NEXT();
686
+ }
687
+ OP(PushPointer) {
688
+ void *ptr;
689
+ if (!call->PushPointer(args[inst->a], inst->type, inst->b2, &ptr)) [[unlikely]]
690
+ return call->env.Null();
691
+
692
+ *(void **)(base + inst->b1) = ptr;
693
+
694
+ NEXT();
695
+ }
696
+ OP(PushRecord) { K_UNREACHABLE(); return call->env.Null(); }
697
+ OP(PushUnion) { K_UNREACHABLE(); return call->env.Null(); }
698
+ OP(PushArray) { K_UNREACHABLE(); return call->env.Null(); }
699
+ OP(PushFloat32) {
700
+ float f;
701
+ if (!TryNumber(call->env, args[inst->a], &f)) [[unlikely]] {
702
+ ThrowError<Napi::TypeError>(call->env, "Unexpected %1 value, expected number", GetValueType(call->instance, args[inst->a]));
703
+ return call->env.Null();
704
+ }
705
+
706
+ memset(base + inst->b1, 0, 8);
707
+ memcpy(base + inst->b1, &f, 4);
708
+
709
+ NEXT();
710
+ }
711
+ OP(PushFloat64) {
712
+ double d;
713
+ if (!TryNumber(call->env, args[inst->a], &d)) [[unlikely]] {
714
+ ThrowError<Napi::TypeError>(call->env, "Unexpected %1 value, expected number", GetValueType(call->instance, args[inst->a]));
715
+ return call->env.Null();
716
+ }
717
+
718
+ *(double *)(base + inst->b1) = d;
719
+
720
+ NEXT();
721
+ }
722
+ OP(PushCallback) {
723
+ void *ptr;
724
+ if (!call->PushCallback(args[inst->a], inst->type, &ptr)) [[unlikely]]
725
+ return call->env.Null();
726
+
727
+ *(void **)(base + inst->b1) = ptr;
728
+
729
+ NEXT();
730
+ }
731
+ OP(PushPrototype) { K_UNREACHABLE(); return call->env.Null(); }
732
+ OP(PushAggregateReg) {
733
+ napi_value arg = args[inst->a];
734
+
735
+ if (!IsObject(call->env, arg)) [[unlikely]] {
736
+ ThrowError<Napi::TypeError>(call->env, "Unexpected %1 value, expected object", GetValueType(call->instance, arg));
737
+ return call->env.Null();
738
+ }
739
+
740
+ uint8_t *ptr = base + inst->b1;
741
+
742
+ if (!call->PushObject(arg, inst->type, ptr))
743
+ return call->env.Null();
744
+
745
+ NEXT();
746
+ }
747
+ OP(PushAggregateStack) {
748
+ napi_value arg = args[inst->a];
749
+
750
+ if (!IsObject(call->env, arg)) [[unlikely]] {
751
+ ThrowError<Napi::TypeError>(call->env, "Unexpected %1 value, expected object", GetValueType(call->instance, arg));
752
+ return call->env.Null();
753
+ }
754
+
755
+ uint8_t *ptr = call->AllocHeap(inst->type->size);
756
+ *(uint8_t **)(base + inst->b1) = ptr;
757
+
758
+ if (!call->PushObject(arg, inst->type, ptr))
759
+ return call->env.Null();
760
+
761
+ NEXT();
762
+ }
763
+ OP(PushHfa32) {
764
+ napi_value arg = args[inst->a];
765
+
766
+ if (!IsObject(call->env, arg)) [[unlikely]] {
767
+ ThrowError<Napi::TypeError>(call->env, "Unexpected %1 value, expected object", GetValueType(call->instance, arg));
768
+ return call->env.Null();
769
+ }
770
+
771
+ uint8_t *ptr = base + inst->b1;
772
+
773
+ if (!call->PushObject(arg, inst->type, ptr))
774
+ return call->env.Null();
775
+
776
+ ExpandFloats(ptr, inst->b2);
777
+
778
+ NEXT();
779
+ }
780
+
781
+ #undef INTEGER_SWAP
782
+ #undef INTEGER
783
+
784
+ #define INTEGER(Suffix, CType) \
785
+ do { \
786
+ uint64_t x0 = WRAP(ForwardCall ## Suffix(call->native, base, &call->saved_sp)).x0; \
787
+ return NewInt(call->env, (CType)x0); \
788
+ } while (false)
789
+ #define INTEGER_SWAP(Suffix, CType) \
790
+ do { \
791
+ uint64_t x0 = WRAP(ForwardCall ## Suffix(call->native, base, &call->saved_sp)).x0; \
792
+ return NewInt(call->env, ReverseBytes((CType)x0)); \
793
+ } while (false)
794
+ #define DISPOSE(Ptr) \
795
+ do { \
796
+ if (inst->type->dispose) { \
797
+ inst->type->dispose(call->env, inst->type, (Ptr)); \
798
+ } \
799
+ } while (false)
800
+
801
+ OP(RunVoid) {
802
+ WRAP(ForwardCallGG(call->native, base, &call->saved_sp));
803
+ return call->env.Undefined();
804
+ }
805
+ OP(RunBool) {
806
+ uint64_t x0 = WRAP(ForwardCallGG(call->native, base, &call->saved_sp).x0);
807
+ return Napi::Boolean::New(call->env, x0 & 0x1);
808
+ }
809
+ OP(RunInt8) { INTEGER(GG, int8_t); }
810
+ OP(RunUInt8) { INTEGER(GG, uint8_t); }
811
+ OP(RunInt16) { INTEGER(GG, int16_t); }
812
+ OP(RunInt16S) { INTEGER_SWAP(GG, int16_t); }
813
+ OP(RunUInt16) { INTEGER(GG, uint16_t); }
814
+ OP(RunUInt16S) { INTEGER_SWAP(GG, uint16_t); }
815
+ OP(RunInt32) { INTEGER(GG, int32_t); }
816
+ OP(RunInt32S) { INTEGER_SWAP(GG, int32_t); }
817
+ OP(RunUInt32) { INTEGER(GG, uint32_t); }
818
+ OP(RunUInt32S) { INTEGER_SWAP(GG, uint32_t); }
819
+ OP(RunInt64) { INTEGER(GG, int64_t); }
820
+ OP(RunInt64S) { INTEGER_SWAP(GG, int64_t); }
821
+ OP(RunUInt64) { INTEGER(GG, uint64_t); }
822
+ OP(RunUInt64S) { INTEGER_SWAP(GG, uint64_t); }
823
+ OP(RunString) {
824
+ uint64_t x0 = WRAP(ForwardCallGG(call->native, base, &call->saved_sp)).x0;
825
+ napi_value value = x0 ? Napi::String::New(call->env, (const char *)x0) : call->env.Null();
826
+ DISPOSE((void *)x0);
827
+ return value;
828
+ }
829
+ OP(RunString16) {
830
+ uint64_t x0 = WRAP(ForwardCallGG(call->native, base, &call->saved_sp)).x0;
831
+ napi_value value = x0 ? Napi::String::New(call->env, (const char16_t *)x0) : call->env.Null();
832
+ DISPOSE((void *)x0);
833
+ return value;
834
+ }
835
+ OP(RunString32) {
836
+ uint64_t x0 = WRAP(ForwardCallGG(call->native, base, &call->saved_sp)).x0;
837
+ napi_value value = x0 ? MakeStringFromUTF32(call->env, (const char32_t *)x0) : call->env.Null();
838
+ DISPOSE((void *)x0);
839
+ return value;
840
+ }
841
+ OP(RunPointer) {
842
+ uint64_t x0 = WRAP(ForwardCallGG(call->native, base, &call->saved_sp)).x0;
843
+ napi_value value = x0 ? WrapPointer(call->env, inst->type, (void *)x0) : call->env.Null();
844
+ DISPOSE((void *)x0);
845
+ return value;
846
+ }
847
+ OP(RunCallback) {
848
+ uint64_t x0 = WRAP(ForwardCallGG(call->native, base, &call->saved_sp)).x0;
849
+ return x0 ? WrapCallback(call->env, inst->type, (void *)x0) : call->env.Null();
850
+ }
851
+ OP(RunRecord) { K_UNREACHABLE(); return call->env.Null(); }
852
+ OP(RunUnion) { K_UNREACHABLE(); return call->env.Null(); }
853
+ OP(RunArray) { K_UNREACHABLE(); return call->env.Null(); }
854
+ OP(RunFloat32) {
855
+ float f = WRAP(ForwardCallF(call->native, base, &call->saved_sp));
856
+ return Napi::Number::New(call->env, (double)f);
857
+ }
858
+ OP(RunFloat64) {
859
+ double d = WRAP(ForwardCallDDDD(call->native, base, &call->saved_sp)).d0;
860
+ return Napi::Number::New(call->env, d);
861
+ }
862
+ OP(RunPrototype) { K_UNREACHABLE(); return call->env.Null(); }
863
+ OP(RunAggregateGG) {
864
+ auto ret = WRAP(ForwardCallGG(call->native, base, &call->saved_sp));
865
+ return DecodeObject(call->env, (const uint8_t *)&ret, inst->type);
866
+ }
867
+ OP(RunAggregateDDDD) {
868
+ auto ret = WRAP(ForwardCallDDDD(call->native, base, &call->saved_sp));
869
+ return DecodeObject(call->env, (const uint8_t *)&ret, inst->type);
870
+ }
871
+ OP(RunHfa32) {
872
+ auto ret = WRAP(ForwardCallDDDD(call->native, base, &call->saved_sp));
873
+ uint8_t *ptr = (uint8_t *)&ret;
874
+ CompactFloats(ptr, inst->a);
875
+ return DecodeObject(call->env, ptr, inst->type);
876
+ }
877
+ OP(RunAggregateStack) {
878
+ uint8_t *ptr = call->AllocHeap(inst->a);
879
+ *(uint8_t **)(base + 8 * 8) = ptr; // x8
880
+ WRAP(ForwardCallGG(call->native, base, &call->saved_sp));
881
+ return DecodeObject(call->env, ptr, inst->type);
882
+ }
883
+ OP(RunVoidX) {
884
+ WRAP(ForwardCallGGX(call->native, base, &call->saved_sp));
885
+ return call->env.Undefined();
886
+ }
887
+ OP(RunBoolX) {
888
+ uint64_t x0 = WRAP(ForwardCallGGX(call->native, base, &call->saved_sp)).x0;
889
+ return Napi::Boolean::New(call->env, x0 & 0x1);
890
+ }
891
+ OP(RunInt8X) { INTEGER(GGX, int8_t); }
892
+ OP(RunUInt8X) { INTEGER(GGX, uint8_t); }
893
+ OP(RunInt16X) { INTEGER(GGX, int16_t); }
894
+ OP(RunInt16SX) { INTEGER_SWAP(GGX, int16_t); }
895
+ OP(RunUInt16X) { INTEGER(GGX, uint16_t); }
896
+ OP(RunUInt16SX) { INTEGER_SWAP(GGX, uint16_t); }
897
+ OP(RunInt32X) { INTEGER(GGX, int32_t); }
898
+ OP(RunInt32SX) { INTEGER_SWAP(GGX, int32_t); }
899
+ OP(RunUInt32X) { INTEGER(GGX, uint32_t); }
900
+ OP(RunUInt32SX) { INTEGER_SWAP(GGX, uint32_t); }
901
+ OP(RunInt64X) { INTEGER(GGX, int64_t); }
902
+ OP(RunInt64SX) { INTEGER_SWAP(GGX, int64_t); }
903
+ OP(RunUInt64X) { INTEGER(GGX, uint64_t); }
904
+ OP(RunUInt64SX) { INTEGER_SWAP(GGX, uint64_t); }
905
+ OP(RunStringX) {
906
+ uint64_t x0 = WRAP(ForwardCallGGX(call->native, base, &call->saved_sp)).x0;
907
+ napi_value value = x0 ? Napi::String::New(call->env, (const char *)x0) : call->env.Null();
908
+ DISPOSE((void *)x0);
909
+ return value;
910
+ }
911
+ OP(RunString16X) {
912
+ uint64_t x0 = WRAP(ForwardCallGGX(call->native, base, &call->saved_sp)).x0;
913
+ napi_value value = x0 ? Napi::String::New(call->env, (const char16_t *)x0) : call->env.Null();
914
+ DISPOSE((void *)x0);
915
+ return value;
916
+ }
917
+ OP(RunString32X) {
918
+ uint64_t x0 = WRAP(ForwardCallGGX(call->native, base, &call->saved_sp)).x0;
919
+ napi_value value = x0 ? MakeStringFromUTF32(call->env, (const char32_t *)x0) : call->env.Null();
920
+ DISPOSE((void *)x0);
921
+ return value;
922
+ }
923
+ OP(RunPointerX) {
924
+ uint64_t x0 = WRAP(ForwardCallGGX(call->native, base, &call->saved_sp)).x0;
925
+ napi_value value = x0 ? WrapPointer(call->env, inst->type, (void *)x0) : call->env.Null();
926
+ DISPOSE((void *)x0);
927
+ return value;
928
+ }
929
+ OP(RunCallbackX) {
930
+ uint64_t x0 = WRAP(ForwardCallGGX(call->native, base, &call->saved_sp)).x0;
931
+ return x0 ? WrapCallback(call->env, inst->type, (void *)x0) : call->env.Null();
932
+ }
933
+ OP(RunRecordX) { K_UNREACHABLE(); return call->env.Null(); }
934
+ OP(RunUnionX) { K_UNREACHABLE(); return call->env.Null(); }
935
+ OP(RunArrayX) { K_UNREACHABLE(); return call->env.Null(); }
936
+ OP(RunFloat32X) {
937
+ float f = WRAP(ForwardCallFX(call->native, base, &call->saved_sp));
938
+ return Napi::Number::New(call->env, (double)f);
939
+ }
940
+ OP(RunFloat64X) {
941
+ double d = WRAP(ForwardCallDDDDX(call->native, base, &call->saved_sp)).d0;
942
+ return Napi::Number::New(call->env, d);
943
+ }
944
+ OP(RunPrototypeX) { K_UNREACHABLE(); return call->env.Null(); }
945
+ OP(RunAggregateGGX) {
946
+ auto ret = WRAP(ForwardCallGGX(call->native, base, &call->saved_sp));
947
+ return DecodeObject(call->env, (const uint8_t *)&ret, inst->type);
948
+ }
949
+ OP(RunAggregateDDDDX) {
950
+ auto ret = WRAP(ForwardCallDDDDX(call->native, base, &call->saved_sp));
951
+ return DecodeObject(call->env, (const uint8_t *)&ret, inst->type);
952
+ }
953
+ OP(RunHfa32X) {
954
+ auto ret = WRAP(ForwardCallDDDDX(call->native, base, &call->saved_sp));
955
+ uint8_t *ptr = (uint8_t *)&ret;
956
+ CompactFloats(ptr, inst->a);
957
+ return DecodeObject(call->env, ptr, inst->type);
958
+ }
959
+ OP(RunAggregateStackX) {
960
+ uint8_t *ptr = call->AllocHeap(inst->a);
961
+ *(uint8_t **)(base + 8 * 8) = ptr; // x8
962
+ WRAP(ForwardCallGGX(call->native, base, &call->saved_sp));
963
+ return DecodeObject(call->env, ptr, inst->type);
964
+ }
965
+
966
+ #undef DISPOSE
967
+ #undef INTEGER_SWAP
968
+ #undef INTEGER
969
+
970
+ #define CALL(Suffix) \
971
+ do { \
972
+ auto ret = WRAP(ForwardCall ## Suffix(call->native, base, &call->saved_sp)); \
973
+ memcpy(base, &ret, K_SIZE(ret)); \
974
+ } while (false)
975
+ #define DISPOSE() \
976
+ do { \
977
+ if (inst->type->dispose) { \
978
+ void *ptr = *(void **)base; \
979
+ inst->type->dispose(call->env, inst->type, ptr); \
980
+ } \
981
+ } while (false)
982
+ #define INTEGER(CType) \
983
+ do { \
984
+ uint64_t x0 = *(uint64_t *)base; \
985
+ return NewInt(call->env, (CType)x0); \
986
+ } while (false)
987
+ #define INTEGER_SWAP(CType) \
988
+ do { \
989
+ uint64_t x0 = *(uint64_t *)base; \
990
+ return NewInt(call->env, ReverseBytes((CType)x0)); \
991
+ } while (false)
992
+
993
+ OP(Yield) {
994
+ call->async_ip = inst + 1;
995
+ return call->env.Null();
996
+ }
997
+
998
+ OP(CallGG) {
999
+ *(uint8_t **)(base + 8 * 8) = base; // x8
1000
+ CALL(GG);
1001
+ return call->env.Null();
1002
+ }
1003
+ OP(CallF) { CALL(F); return call->env.Null(); }
1004
+ OP(CallDDDD) { CALL(DDDD); return call->env.Null(); }
1005
+ OP(CallStack) {
1006
+ uint8_t *ptr = call->AllocHeap(inst->a);
1007
+ *(uint8_t **)(base + 8 * 8) = ptr; // x8
1008
+ CALL(GG);
1009
+ *(uint8_t **)base = ptr; // Store pointer for ReturnAggregateStack
1010
+ return call->env.Null();
1011
+ }
1012
+ OP(CallGGX) {
1013
+ *(uint8_t **)(base + 8 * 8) = base; // x8
1014
+ CALL(GGX);
1015
+ return call->env.Null();
1016
+ }
1017
+ OP(CallFX) { CALL(FX); return call->env.Null(); }
1018
+ OP(CallDDDDX) { CALL(DDDDX); return call->env.Null(); }
1019
+ OP(CallStackX) {
1020
+ uint8_t *ptr = call->AllocHeap(inst->a);
1021
+ *(uint8_t **)(base + 8 * 8) = ptr; // x8
1022
+ CALL(GGX);
1023
+ *(uint8_t **)base = ptr; // Store pointer for ReturnAggregateStack
1024
+ return call->env.Null();
1025
+ }
1026
+
1027
+ OP(ReturnVoid) { return call->env.Undefined(); }
1028
+ OP(ReturnBool) {
1029
+ uint64_t x0 = *(uint64_t *)base;
1030
+ return Napi::Boolean::New(call->env, x0 & 0x1);
1031
+ }
1032
+ OP(ReturnInt8) { INTEGER(int8_t); }
1033
+ OP(ReturnUInt8) { INTEGER(uint8_t); }
1034
+ OP(ReturnInt16) { INTEGER(int16_t); }
1035
+ OP(ReturnInt16S) { INTEGER_SWAP(int16_t); }
1036
+ OP(ReturnUInt16) { INTEGER(uint16_t); }
1037
+ OP(ReturnUInt16S) { INTEGER_SWAP(uint16_t); }
1038
+ OP(ReturnInt32) { INTEGER(int32_t); }
1039
+ OP(ReturnInt32S) { INTEGER_SWAP(int32_t); }
1040
+ OP(ReturnUInt32) { INTEGER(uint32_t); }
1041
+ OP(ReturnUInt32S) { INTEGER_SWAP(uint32_t); }
1042
+ OP(ReturnInt64) { INTEGER(int64_t); }
1043
+ OP(ReturnInt64S) { INTEGER_SWAP(int64_t); }
1044
+ OP(ReturnUInt64) { INTEGER(uint64_t); }
1045
+ OP(ReturnUInt64S) { INTEGER_SWAP(uint64_t); }
1046
+ OP(ReturnString) {
1047
+ uint64_t x0 = *(uint64_t *)base;
1048
+ napi_value value = x0 ? Napi::String::New(call->env, (const char *)x0) : call->env.Null();
1049
+ DISPOSE();
1050
+ return value;
1051
+ }
1052
+ OP(ReturnString16) {
1053
+ uint64_t x0 = *(uint64_t *)base;
1054
+ napi_value value = x0 ? Napi::String::New(call->env, (const char16_t *)x0) : call->env.Null();
1055
+ DISPOSE();
1056
+ return value;
1057
+ }
1058
+ OP(ReturnString32) {
1059
+ uint64_t x0 = *(uint64_t *)base;
1060
+ napi_value value = x0 ? MakeStringFromUTF32(call->env, (const char32_t *)x0) : call->env.Null();
1061
+ DISPOSE();
1062
+ return value;
1063
+ }
1064
+ OP(ReturnPointer) {
1065
+ uint64_t x0 = *(uint64_t *)base;
1066
+ napi_value value = x0 ? WrapPointer(call->env, inst->type, (void *)x0) : call->env.Null();
1067
+ DISPOSE();
1068
+ return value;
1069
+ }
1070
+ OP(ReturnCallback) {
1071
+ uint64_t x0 = *(uint64_t *)base;
1072
+ return x0 ? WrapCallback(call->env, inst->type, (void *)x0) : call->env.Null();
1073
+ }
1074
+ OP(ReturnRecord) { K_UNREACHABLE(); return call->env.Null(); }
1075
+ OP(ReturnUnion) { K_UNREACHABLE(); return call->env.Null(); }
1076
+ OP(ReturnArray) { K_UNREACHABLE(); return call->env.Null(); }
1077
+ OP(ReturnFloat32) {
1078
+ float f = *(float *)base;
1079
+ return Napi::Number::New(call->env, (double)f);
1080
+ }
1081
+ OP(ReturnFloat64) {
1082
+ double d = *(double *)base;
1083
+ return Napi::Number::New(call->env, d);
1084
+ }
1085
+ OP(ReturnPrototype) { K_UNREACHABLE(); return call->env.Null(); }
1086
+ OP(ReturnAggregateReg) {
1087
+ return DecodeObject(call->env, base, inst->type);
1088
+ }
1089
+ OP(ReturnAggregateStack) {
1090
+ const uint8_t *ptr = *(const uint8_t **)base;
1091
+ return DecodeObject(call->env, ptr, inst->type);
1092
+ }
1093
+ OP(ReturnHfa32) {
1094
+ CompactFloats(base, inst->a);
1095
+ return DecodeObject(call->env, base, inst->type);
1096
+ }
1097
+
1098
+ #if defined(_M_ARM64EC)
1099
+ OP(SetVariadicRegisters) {
1100
+ uint64_t *gpr_ptr = (uint64_t *)base;
1101
+
1102
+ gpr_ptr[4] = (uint64_t)base + 19 * 8;
1103
+ gpr_ptr[5] = inst->a;
1104
+
1105
+ NEXT();
1106
+ }
1107
+ #endif
1108
+
1109
+ #undef INTEGER_SWAP
1110
+ #undef INTEGER
1111
+ #undef DISPOSE
1112
+ #undef CALL
1113
+
1114
+ #if defined(MUST_TAIL)
1115
+ ForwardFunc *const ForwardDispatch[256] = {
1116
+ #define PRIMITIVE(Name) HandlePush ## Name,
1117
+ #include "../primitives.inc"
1118
+ HandlePushAggregateReg,
1119
+ HandlePushAggregateStack,
1120
+ HandlePushHfa32,
1121
+ #define PRIMITIVE(Name) HandleRun ## Name,
1122
+ #include "../primitives.inc"
1123
+ HandleRunAggregateGG,
1124
+ HandleRunAggregateDDDD,
1125
+ HandleRunHfa32,
1126
+ HandleRunAggregateStack,
1127
+ #define PRIMITIVE(Name) HandleRun ## Name ## X,
1128
+ #include "../primitives.inc"
1129
+ HandleRunAggregateGGX,
1130
+ HandleRunAggregateDDDDX,
1131
+ HandleRunHfa32X,
1132
+ HandleRunAggregateStackX,
1133
+ HandleYield,
1134
+ HandleCallGG,
1135
+ HandleCallF,
1136
+ HandleCallDDDD,
1137
+ HandleCallStack,
1138
+ HandleCallGGX,
1139
+ HandleCallFX,
1140
+ HandleCallDDDDX,
1141
+ HandleCallStackX,
1142
+ #define PRIMITIVE(Name) HandleReturn ## Name,
1143
+ #include "../primitives.inc"
1144
+ HandleReturnAggregateReg,
1145
+ HandleReturnAggregateStack,
1146
+ HandleReturnHfa32,
1147
+ #if defined(_M_ARM64EC)
1148
+ HandleSetVariadicRegisters
1149
+ #endif
1150
+ };
1151
+
1152
+ FORCE_INLINE napi_value RunLoop(CallData *call, napi_value *args, uint8_t *base, const AbiInstruction *inst)
1153
+ {
1154
+ return ((ForwardFunc *)inst->op)(call, args, base, inst);
1155
+ }
1156
+ #else
1157
+ }
1158
+ }
1159
+
1160
+ K_UNREACHABLE();
1161
+ }
1162
+ #endif
1163
+
1164
+ #undef WRAP
1165
+
1166
+ #undef NEXT
1167
+ #undef OP
1168
+ }
1169
+
1170
+ #pragma GCC diagnostic pop
1171
+
1172
+ napi_value CallData::Run(const FunctionInfo *func, napi_value *args)
1173
+ {
1174
+ uint8_t *base = AllocStack<uint8_t>(func->stk_size);
1175
+ if (!base) [[unlikely]]
1176
+ return env.Null();
1177
+
1178
+ const AbiInstruction *first = func->sync.ptr;
1179
+ return RunLoop(this, args, base, first);
1180
+ }
1181
+
1182
+ bool CallData::PrepareAsync(const FunctionInfo *func, napi_value *args)
1183
+ {
1184
+ uint8_t *base = AllocStack<uint8_t>(func->stk_size);
1185
+ if (!base) [[unlikely]]
1186
+ return env.Null();
1187
+ async_base = base;
1188
+
1189
+ const AbiInstruction *first = func->async.ptr;
1190
+ return RunLoop(this, args, base, first);
1191
+ }
1192
+
1193
+ void CallData::ExecuteAsync()
1194
+ {
1195
+ const AbiInstruction *next = async_ip++;
1196
+ RunLoop(this, nullptr, async_base, next);
1197
+ }
1198
+
1199
+ napi_value CallData::EndAsync()
1200
+ {
1201
+ const AbiInstruction *next = async_ip++;
1202
+ return RunLoop(this, nullptr, async_base, next);
1203
+ }
1204
+
1205
+ void CallData::Relay(Size idx, uint8_t *sp)
1206
+ {
1207
+ TrampolineInfo *trampoline = &shared.trampolines[idx];
1208
+
1209
+ uint8_t *in_ptr = sp + 48;
1210
+ BackRegisters *out_reg = (BackRegisters *)sp;
1211
+
1212
+ const FunctionInfo *proto = trampoline->proto;
1213
+ Napi::Function func = trampoline->func.Value();
1214
+
1215
+ K_DEFER_N(err_guard) {
1216
+ trampoline->state = -1;
1217
+ memset(out_reg, 0, K_SIZE(*out_reg));
1218
+ };
1219
+
1220
+ LocalArray<napi_value, MaxParameters + 1> arguments;
1221
+
1222
+ arguments.Append(!trampoline->recv.IsEmpty() ? trampoline->recv.Value() : env.Undefined());
1223
+
1224
+ #define POP_INTEGER(CType) \
1225
+ do { \
1226
+ const uint8_t *src = in_ptr + param.abi.offset; \
1227
+ CType v = *(const CType *)src; \
1228
+ \
1229
+ Napi::Value arg = NewInt(env, v); \
1230
+ arguments.Append(arg); \
1231
+ } while (false)
1232
+ #define POP_INTEGER_SWAP(CType) \
1233
+ do { \
1234
+ const uint8_t *src = in_ptr + param.abi.offset; \
1235
+ CType v = *(const CType *)src; \
1236
+ \
1237
+ Napi::Value arg = NewInt(env, ReverseBytes(v)); \
1238
+ arguments.Append(arg); \
1239
+ } while (false)
1240
+
1241
+ // Convert to JS arguments
1242
+ for (Size i = 0; i < proto->parameters.len; i++) {
1243
+ const ParameterInfo &param = proto->parameters[i];
1244
+ K_ASSERT(param.directions >= 1 && param.directions <= 3);
1245
+
1246
+ switch (param.type->primitive) {
1247
+ case PrimitiveKind::Void: { K_UNREACHABLE(); } break;
1248
+
1249
+ case PrimitiveKind::Bool: {
1250
+ const uint8_t *src = in_ptr + param.abi.offset;
1251
+ bool b = *(bool *)src;
1252
+
1253
+ Napi::Value arg = Napi::Boolean::New(env, b);
1254
+ arguments.Append(arg);
1255
+ } break;
1256
+
1257
+ case PrimitiveKind::Int8: { POP_INTEGER(int8_t); } break;
1258
+ case PrimitiveKind::UInt8: { POP_INTEGER(uint8_t); } break;
1259
+ case PrimitiveKind::Int16: { POP_INTEGER(int16_t); } break;
1260
+ case PrimitiveKind::Int16S: { POP_INTEGER_SWAP(int16_t); } break;
1261
+ case PrimitiveKind::UInt16: { POP_INTEGER(uint16_t); } break;
1262
+ case PrimitiveKind::UInt16S: { POP_INTEGER_SWAP(uint16_t); } break;
1263
+ case PrimitiveKind::Int32: { POP_INTEGER(int32_t); } break;
1264
+ case PrimitiveKind::Int32S: { POP_INTEGER_SWAP(int32_t); } break;
1265
+ case PrimitiveKind::UInt32: { POP_INTEGER(uint32_t); } break;
1266
+ case PrimitiveKind::UInt32S: { POP_INTEGER_SWAP(uint32_t); } break;
1267
+ case PrimitiveKind::Int64: { POP_INTEGER(int64_t); } break;
1268
+ case PrimitiveKind::Int64S: { POP_INTEGER_SWAP(int64_t); } break;
1269
+ case PrimitiveKind::UInt64: { POP_INTEGER(uint64_t); } break;
1270
+ case PrimitiveKind::UInt64S: { POP_INTEGER_SWAP(uint64_t); } break;
1271
+
1272
+ case PrimitiveKind::String: {
1273
+ const uint8_t *src = in_ptr + param.abi.offset;
1274
+ const char *str = *(const char **)src;
1275
+
1276
+ Napi::Value arg = str ? Napi::String::New(env, str) : env.Null();
1277
+ arguments.Append(arg);
1278
+
1279
+ if (param.type->dispose) {
1280
+ param.type->dispose(env, param.type, str);
1281
+ }
1282
+ } break;
1283
+ case PrimitiveKind::String16: {
1284
+ const uint8_t *src = in_ptr + param.abi.offset;
1285
+ const char16_t *str16 = *(const char16_t **)src;
1286
+
1287
+ Napi::Value arg = str16 ? Napi::String::New(env, str16) : env.Null();
1288
+ arguments.Append(arg);
1289
+
1290
+ if (param.type->dispose) {
1291
+ param.type->dispose(env, param.type, str16);
1292
+ }
1293
+ } break;
1294
+ case PrimitiveKind::String32: {
1295
+ const uint8_t *src = in_ptr + param.abi.offset;
1296
+ const char32_t *str32 = *(const char32_t **)src;
1297
+
1298
+ Napi::Value arg = str32 ? MakeStringFromUTF32(env, str32) : env.Null();
1299
+ arguments.Append(arg);
1300
+ } break;
1301
+
1302
+ case PrimitiveKind::Pointer: {
1303
+ const uint8_t *src = in_ptr + param.abi.offset;
1304
+ void *ptr2 = *(void **)src;
1305
+
1306
+ Napi::Value p = ptr2 ? WrapPointer(env, param.type->ref.type, ptr2) : env.Null();
1307
+ arguments.Append(p);
1308
+
1309
+ if (param.type->dispose) {
1310
+ param.type->dispose(env, param.type, ptr2);
1311
+ }
1312
+ } break;
1313
+
1314
+ case PrimitiveKind::Record:
1315
+ case PrimitiveKind::Union: {
1316
+ uint8_t *ptr = in_ptr + param.abi.offset;
1317
+ uint8_t *src = param.abi.indirect ? *(uint8_t **)ptr : ptr;
1318
+
1319
+ CompactFloats(src, param.abi.hfa32);
1320
+
1321
+ Napi::Object obj = DecodeObject(env, src, param.type);
1322
+ arguments.Append(obj);
1323
+ } break;
1324
+ case PrimitiveKind::Array: { K_UNREACHABLE(); } break;
1325
+
1326
+ case PrimitiveKind::Float32: {
1327
+ const uint8_t *src = in_ptr + param.abi.offset;
1328
+ float f = *(float *)src;
1329
+
1330
+ Napi::Value arg = Napi::Number::New(env, (double)f);
1331
+ arguments.Append(arg);
1332
+ } break;
1333
+ case PrimitiveKind::Float64: {
1334
+ const uint8_t *src = in_ptr + param.abi.offset;
1335
+ double d = *(double *)src;
1336
+
1337
+ Napi::Value arg = Napi::Number::New(env, d);
1338
+ arguments.Append(arg);
1339
+ } break;
1340
+
1341
+ case PrimitiveKind::Callback: {
1342
+ const uint8_t *src = in_ptr + param.abi.offset;
1343
+ void *ptr2 = *(void **)src;
1344
+
1345
+ Napi::Value p = ptr2 ? WrapCallback(env, param.type->ref.type, ptr2) : env.Null();
1346
+ arguments.Append(p);
1347
+
1348
+ if (param.type->dispose) {
1349
+ param.type->dispose(env, param.type, ptr2);
1350
+ }
1351
+ } break;
1352
+
1353
+ case PrimitiveKind::Prototype: { K_UNREACHABLE(); } break;
1354
+ }
1355
+ }
1356
+
1357
+ #undef POP_INTEGER_SWAP
1358
+ #undef POP_INTEGER
1359
+
1360
+ const TypeInfo *type = proto->ret.type;
1361
+
1362
+ // Make the call!
1363
+ Napi::Value value = func.Call(arguments[0], arguments.len - 1, arguments.data + 1);
1364
+
1365
+ if (env.IsExceptionPending()) [[unlikely]]
1366
+ return;
1367
+
1368
+ #define RETURN_INTEGER(CType) \
1369
+ do { \
1370
+ CType v; \
1371
+ if (!TryNumber(env, value, &v)) [[unlikely]] { \
1372
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
1373
+ return; \
1374
+ } \
1375
+ \
1376
+ out_reg->x0 = (uint64_t)v; \
1377
+ } while (false)
1378
+ #define RETURN_INTEGER_SWAP(CType) \
1379
+ do { \
1380
+ CType v; \
1381
+ if (!TryNumber(env, value, &v)) [[unlikely]] { \
1382
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
1383
+ return; \
1384
+ } \
1385
+ \
1386
+ out_reg->x0 = (uint64_t)ReverseBytes(v); \
1387
+ } while (false)
1388
+
1389
+ // Convert the result
1390
+ switch (type->primitive) {
1391
+ case PrimitiveKind::Void: {} break;
1392
+
1393
+ case PrimitiveKind::Bool: {
1394
+ bool b;
1395
+ if (napi_get_value_bool(env, value, &b) != napi_ok) [[unlikely]] {
1396
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected boolean", GetValueType(instance, value));
1397
+ return;
1398
+ }
1399
+
1400
+ out_reg->x0 = (uint64_t)b;
1401
+ } break;
1402
+
1403
+ case PrimitiveKind::Int8: { RETURN_INTEGER(int8_t); } break;
1404
+ case PrimitiveKind::UInt8: { RETURN_INTEGER(uint8_t); } break;
1405
+ case PrimitiveKind::Int16: { RETURN_INTEGER(int16_t); } break;
1406
+ case PrimitiveKind::Int16S: { RETURN_INTEGER_SWAP(int16_t); } break;
1407
+ case PrimitiveKind::UInt16: { RETURN_INTEGER(uint16_t); } break;
1408
+ case PrimitiveKind::UInt16S: { RETURN_INTEGER_SWAP(uint16_t); } break;
1409
+ case PrimitiveKind::Int32: { RETURN_INTEGER(int32_t); } break;
1410
+ case PrimitiveKind::Int32S: { RETURN_INTEGER_SWAP(int32_t); } break;
1411
+ case PrimitiveKind::UInt32: { RETURN_INTEGER(uint32_t); } break;
1412
+ case PrimitiveKind::UInt32S: { RETURN_INTEGER_SWAP(uint32_t); } break;
1413
+ case PrimitiveKind::Int64: { RETURN_INTEGER(int64_t); } break;
1414
+ case PrimitiveKind::Int64S: { RETURN_INTEGER_SWAP(int64_t); } break;
1415
+ case PrimitiveKind::UInt64: { RETURN_INTEGER(uint64_t); } break;
1416
+ case PrimitiveKind::UInt64S: { RETURN_INTEGER_SWAP(uint64_t); } break;
1417
+
1418
+ case PrimitiveKind::String: {
1419
+ const char *str;
1420
+ if (!PushString(value, 1, &str)) [[unlikely]]
1421
+ return;
1422
+
1423
+ out_reg->x0 = (uint64_t)str;
1424
+ } break;
1425
+ case PrimitiveKind::String16: {
1426
+ const char16_t *str16;
1427
+ if (!PushString16(value, 1, &str16)) [[unlikely]]
1428
+ return;
1429
+
1430
+ out_reg->x0 = (uint64_t)str16;
1431
+ } break;
1432
+ case PrimitiveKind::String32: {
1433
+ const char32_t *str32;
1434
+ if (!PushString32(value, 1, &str32)) [[unlikely]]
1435
+ return;
1436
+
1437
+ out_reg->x0 = (uint64_t)str32;
1438
+ } break;
1439
+
1440
+ case PrimitiveKind::Pointer: {
1441
+ void *ptr;
1442
+ if (!PushPointer(value, type, 1, &ptr)) [[unlikely]]
1443
+ return;
1444
+
1445
+ out_reg->x0 = (uint64_t)ptr;
1446
+ } break;
1447
+
1448
+ case PrimitiveKind::Record:
1449
+ case PrimitiveKind::Union: {
1450
+ if (!IsObject(env, value)) [[unlikely]] {
1451
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
1452
+ return;
1453
+ }
1454
+
1455
+ Napi::Object obj = value.As<Napi::Object>();
1456
+
1457
+ if (proto->ret.abi.regular) {
1458
+ uint8_t *dest = (uint8_t *)&out_reg + proto->ret.abi.offset;
1459
+ if (!PushObject(obj, type, dest))
1460
+ return;
1461
+ ExpandFloats(dest, proto->ret.abi.hfa32);
1462
+ } else {
1463
+ uint64_t *gpr_ptr = (uint64_t *)in_ptr;
1464
+ uint8_t *dest = (uint8_t *)gpr_ptr[8]; // r8
1465
+
1466
+ if (!PushObject(obj, type, dest))
1467
+ return;
1468
+ }
1469
+ } break;
1470
+ case PrimitiveKind::Array: { K_UNREACHABLE(); } break;
1471
+
1472
+ case PrimitiveKind::Float32: {
1473
+ float f;
1474
+ if (!TryNumber(env, value, &f)) [[unlikely]] {
1475
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
1476
+ return;
1477
+ }
1478
+
1479
+ memset((uint8_t *)&out_reg->d0, 0, 8);
1480
+ memcpy(&out_reg->d0, &f, 4);
1481
+ } break;
1482
+ case PrimitiveKind::Float64: {
1483
+ double d;
1484
+ if (!TryNumber(env, value, &d)) [[unlikely]] {
1485
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
1486
+ return;
1487
+ }
1488
+
1489
+ out_reg->d0 = d;
1490
+ } break;
1491
+
1492
+ case PrimitiveKind::Callback: {
1493
+ void *ptr;
1494
+ if (!PushCallback(value, type, &ptr)) [[unlikely]]
1495
+ return;
1496
+
1497
+ out_reg->x0 = (uint64_t)ptr;
1498
+ } break;
1499
+
1500
+ case PrimitiveKind::Prototype: { K_UNREACHABLE(); } break;
1501
+ }
1502
+
1503
+ #undef RETURN_INTEGER_SWAP
1504
+ #undef RETURN_INTEGER
1505
+
1506
+ err_guard.Disable();
1507
+ }
1508
+
1509
+ }
1510
+
1511
+ #endif