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,1121 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // SPDX-FileCopyrightText: 2025 Niels Martignène <niels.martignene@protonmail.com>
3
+
4
+ #if defined(_WIN32) && (defined(__x86_64__) || defined(_M_AMD64))
5
+
6
+ #include "lib/native/base/base.hh"
7
+ #include "../ffi.hh"
8
+ #include "../call.hh"
9
+ #include "../util.hh"
10
+ #include "../win32.hh"
11
+
12
+ #include <napi.h>
13
+
14
+ namespace K {
15
+
16
+ struct BackRegisters {
17
+ uint64_t rax;
18
+ double xmm0;
19
+ };
20
+
21
+ extern "C" uint64_t ForwardCallG(const void *func, uint8_t *sp, uint8_t **out_saved_sp);
22
+ extern "C" float ForwardCallF(const void *func, uint8_t *sp, uint8_t **out_saved_sp);
23
+ extern "C" double ForwardCallD(const void *func, uint8_t *sp, uint8_t **out_saved_sp);
24
+ extern "C" uint64_t ForwardCallGX(const void *func, uint8_t *sp, uint8_t **out_saved_sp);
25
+ extern "C" float ForwardCallFX(const void *func, uint8_t *sp, uint8_t **out_saved_sp);
26
+ extern "C" double ForwardCallDX(const void *func, uint8_t *sp, uint8_t **out_saved_sp);
27
+
28
+ enum class AbiOpcode {
29
+ #define PRIMITIVE(Name) Push ## Name,
30
+ #include "../primitives.inc"
31
+ PushAggregateReg,
32
+ PushAggregateStack,
33
+ #define PRIMITIVE(Name) Run ## Name,
34
+ #include "../primitives.inc"
35
+ RunAggregateReg,
36
+ RunAggregateStack,
37
+ #define PRIMITIVE(Name) Run ## Name ## X,
38
+ #include "../primitives.inc"
39
+ RunAggregateRegX,
40
+ RunAggregateStackX,
41
+ Yield,
42
+ CallG,
43
+ CallF,
44
+ CallD,
45
+ CallStack,
46
+ CallGX,
47
+ CallFX,
48
+ CallDX,
49
+ CallStackX,
50
+ #define PRIMITIVE(Name) Return ## Name,
51
+ #include "../primitives.inc"
52
+ ReturnAggregate
53
+ };
54
+
55
+ namespace {
56
+ #if defined(MUST_TAIL)
57
+ PRESERVE_NONE typedef napi_value ForwardFunc(CallData *call, napi_value *args, uint64_t *base, const AbiInstruction *inst);
58
+
59
+ extern ForwardFunc *const ForwardDispatch[256];
60
+
61
+ inline void *Code2Op(AbiOpcode code)
62
+ {
63
+ return (void *)ForwardDispatch[(int)code];
64
+ }
65
+ #else
66
+ inline void *Code2Op(AbiOpcode code)
67
+ {
68
+ return (void *)code;
69
+ }
70
+ #endif
71
+ }
72
+
73
+ bool AnalyseFunction(Napi::Env, InstanceData *, FunctionInfo *func)
74
+ {
75
+ func->ret.regular = IsRegularSize(func->ret.type->size, 8);
76
+
77
+ for (Size i = 0; i < func->parameters.len; i++) {
78
+ int16_t arg = (int16_t)(!func->ret.regular + i);
79
+ ParameterInfo &param = func->parameters[i];
80
+
81
+ param.regular = IsRegularSize(param.type->size, 8);
82
+
83
+ if (param.type->primitive == PrimitiveKind::Record || param.type->primitive == PrimitiveKind::Union) {
84
+ AbiOpcode code = param.regular ? AbiOpcode::PushAggregateReg : AbiOpcode::PushAggregateStack;
85
+
86
+ func->sync.Append({ .op = Code2Op(code), .a = param.offset, .b1 = arg, .b2 = (int16_t)param.directions, .type = param.type });
87
+ func->async.Append({ .op = Code2Op(code), .a = param.offset, .b1 = arg, .b2 = (int16_t)param.directions, .type = param.type });
88
+ } else {
89
+ int delta = (int)AbiOpcode::PushVoid - (int)PrimitiveKind::Void;
90
+ AbiOpcode code = (AbiOpcode)((int)param.type->primitive + delta);
91
+
92
+ func->sync.Append({ .op = Code2Op(code), .a = param.offset, .b1 = arg, .b2 = (int16_t)param.directions, .type = param.type });
93
+ func->async.Append({ .op = Code2Op(code), .a = param.offset, .b1 = arg, .b2 = (int16_t)param.directions, .type = param.type });
94
+ }
95
+
96
+ func->forward_fp |= IsFloat(param.type);
97
+ }
98
+
99
+ // At least 4 parameter registers
100
+ {
101
+ Size count = std::max((Size)4, func->parameters.len + !func->ret.regular);
102
+ func->stk_size = AlignLen(8 * count, 16);
103
+ }
104
+
105
+ func->async.Append({ .op = Code2Op(AbiOpcode::Yield) });
106
+
107
+ switch (func->ret.type->primitive) {
108
+ case PrimitiveKind::Void:
109
+ case PrimitiveKind::Bool:
110
+ case PrimitiveKind::Int8:
111
+ case PrimitiveKind::UInt8:
112
+ case PrimitiveKind::Int16:
113
+ case PrimitiveKind::Int16S:
114
+ case PrimitiveKind::UInt16:
115
+ case PrimitiveKind::UInt16S:
116
+ case PrimitiveKind::Int32:
117
+ case PrimitiveKind::Int32S:
118
+ case PrimitiveKind::UInt32:
119
+ case PrimitiveKind::UInt32S:
120
+ case PrimitiveKind::Int64:
121
+ case PrimitiveKind::Int64S:
122
+ case PrimitiveKind::UInt64:
123
+ case PrimitiveKind::UInt64S:
124
+ case PrimitiveKind::String:
125
+ case PrimitiveKind::String16:
126
+ case PrimitiveKind::String32: {
127
+ if (func->forward_fp) {
128
+ int delta = (int)AbiOpcode::RunVoidX - (int)PrimitiveKind::Void;
129
+ AbiOpcode run = (AbiOpcode)((int)func->ret.type->primitive + delta);
130
+
131
+ func->sync.Append({ .op = Code2Op(run), .type = func->ret.type });
132
+ } else {
133
+ int delta = (int)AbiOpcode::RunVoid - (int)PrimitiveKind::Void;
134
+ AbiOpcode run = (AbiOpcode)((int)func->ret.type->primitive + delta);
135
+
136
+ func->sync.Append({ .op = Code2Op(run), .type = func->ret.type });
137
+ }
138
+
139
+ // Async
140
+ {
141
+ int delta = (int)AbiOpcode::ReturnVoid - (int)PrimitiveKind::Void;
142
+ AbiOpcode call = func->forward_fp ? AbiOpcode::CallGX : AbiOpcode::CallG;
143
+ AbiOpcode ret = (AbiOpcode)((int)func->ret.type->primitive + delta);
144
+
145
+ func->async.Append({ .op = Code2Op(call) });
146
+ func->async.Append({ .op = Code2Op(ret), .type = func->ret.type });
147
+ }
148
+ } break;
149
+
150
+ case PrimitiveKind::Pointer: {
151
+ AbiOpcode run = func->forward_fp ? AbiOpcode::RunPointerX : AbiOpcode::RunPointer;
152
+ AbiOpcode call = func->forward_fp ? AbiOpcode::CallGX : AbiOpcode::CallG;
153
+
154
+ func->sync.Append({ .op = Code2Op(run), .type = func->ret.type->ref.type });
155
+ func->async.Append({ .op = Code2Op(call) });
156
+ func->async.Append({ .op = Code2Op(AbiOpcode::ReturnPointer), .type = func->ret.type->ref.type });
157
+ } break;
158
+ case PrimitiveKind::Callback: {
159
+ AbiOpcode run = func->forward_fp ? AbiOpcode::RunCallbackX : AbiOpcode::RunCallback;
160
+ AbiOpcode call = func->forward_fp ? AbiOpcode::CallGX : AbiOpcode::CallG;
161
+
162
+ func->sync.Append({ .op = Code2Op(run), .type = func->ret.type });
163
+ func->async.Append({ .op = Code2Op(call) });
164
+ func->async.Append({ .op = Code2Op(AbiOpcode::ReturnCallback), .type = func->ret.type });
165
+ } break;
166
+
167
+ case PrimitiveKind::Record:
168
+ case PrimitiveKind::Union: {
169
+ if (func->ret.regular) {
170
+ AbiOpcode run = func->forward_fp ? AbiOpcode::RunAggregateRegX : AbiOpcode::RunAggregateReg;
171
+ AbiOpcode call = func->forward_fp ? AbiOpcode::CallGX : AbiOpcode::CallG;
172
+
173
+ func->sync.Append({ .op = Code2Op(run), .type = func->ret.type });
174
+ func->async.Append({ .op = Code2Op(call) });
175
+ func->async.Append({ .op = Code2Op(AbiOpcode::ReturnAggregate), .type = func->ret.type });
176
+ } else {
177
+ AbiOpcode run = func->forward_fp ? AbiOpcode::RunAggregateStackX : AbiOpcode::RunAggregateStack;
178
+ AbiOpcode call = func->forward_fp ? AbiOpcode::CallStackX : AbiOpcode::CallStack;
179
+
180
+ func->sync.Append({ .op = Code2Op(run), .a = (int32_t)func->ret.type->size, .type = func->ret.type });
181
+ func->async.Append({ .op = Code2Op(call), .a = (int32_t)func->ret.type->size });
182
+ func->async.Append({ .op = Code2Op(AbiOpcode::ReturnAggregate), .type = func->ret.type });
183
+ }
184
+ } break;
185
+ case PrimitiveKind::Array: { K_UNREACHABLE(); } break;
186
+
187
+ case PrimitiveKind::Float32: {
188
+ AbiOpcode run = func->forward_fp ? AbiOpcode::RunFloat32X : AbiOpcode::RunFloat32;
189
+ AbiOpcode call = func->forward_fp ? AbiOpcode::CallFX : AbiOpcode::CallF;
190
+
191
+ func->sync.Append({ .op = Code2Op(run), .type = func->ret.type });
192
+ func->async.Append({ .op = Code2Op(call) });
193
+ func->async.Append({ .op = Code2Op(AbiOpcode::ReturnFloat32), .type = func->ret.type });
194
+ } break;
195
+ case PrimitiveKind::Float64: {
196
+ AbiOpcode run = func->forward_fp ? AbiOpcode::RunFloat64X : AbiOpcode::RunFloat64;
197
+ AbiOpcode call = func->forward_fp ? AbiOpcode::CallDX : AbiOpcode::CallD;
198
+
199
+ func->sync.Append({ .op = Code2Op(run), .type = func->ret.type });
200
+ func->async.Append({ .op = Code2Op(call) });
201
+ func->async.Append({ .op = Code2Op(AbiOpcode::ReturnFloat64), .type = func->ret.type });
202
+ } break;
203
+
204
+ case PrimitiveKind::Prototype: { K_UNREACHABLE(); } break;
205
+ }
206
+
207
+ return true;
208
+ }
209
+
210
+ #if defined(__GNUC__) || defined(__clang__)
211
+ #pragma GCC diagnostic push
212
+ #pragma GCC diagnostic ignored "-Wunused-parameter"
213
+ #endif
214
+
215
+ namespace {
216
+ #if defined(MUST_TAIL)
217
+ #define OP(Code) \
218
+ PRESERVE_NONE napi_value Handle ## Code(CallData *call, napi_value *args, uint64_t *base, const AbiInstruction *inst)
219
+ #define NEXT() \
220
+ do { \
221
+ const AbiInstruction *next = inst + 1; \
222
+ MUST_TAIL return ((ForwardFunc *)next->op)(call, args, base, next); \
223
+ } while (false)
224
+ #else
225
+ #define OP(Code) \
226
+ case (int)AbiOpcode::Code:
227
+ #define NEXT() \
228
+ break
229
+
230
+ napi_value RunLoop(CallData *call, napi_value *args, uint64_t *base, const AbiInstruction *inst)
231
+ {
232
+ for (;; ++inst) {
233
+ switch ((intptr_t)inst->op) {
234
+ #endif
235
+
236
+ #define WRAP(Expr) \
237
+ [&]() { \
238
+ TEB *teb = GetTEB(); \
239
+ \
240
+ ADJUST_TEB(teb, call->mem->stack0.ptr, call->mem->stack0.end); \
241
+ \
242
+ return (Expr); \
243
+ }()
244
+
245
+ #define INTEGER(CType) \
246
+ do { \
247
+ CType v; \
248
+ if (!TryNumber(call->env, args[inst->a], &v)) [[unlikely]] { \
249
+ ThrowError<Napi::TypeError>(call->env, "Unexpected %1 value, expected number", GetValueType(call->instance, args[inst->a])); \
250
+ return call->env.Null(); \
251
+ } \
252
+ \
253
+ *(base + inst->b1) = (uint64_t)v; \
254
+ } while (false)
255
+ #define INTEGER_SWAP(CType) \
256
+ do { \
257
+ CType v; \
258
+ if (!TryNumber(call->env, args[inst->a], &v)) [[unlikely]] { \
259
+ ThrowError<Napi::TypeError>(call->env, "Unexpected %1 value, expected number", GetValueType(call->instance, args[inst->a])); \
260
+ return call->env.Null(); \
261
+ } \
262
+ \
263
+ *(base + inst->b1) = (uint64_t)ReverseBytes(v); \
264
+ } while (false)
265
+
266
+ OP(PushVoid) { K_UNREACHABLE(); return call->env.Null(); }
267
+ OP(PushBool) {
268
+ bool b;
269
+ if (napi_get_value_bool(call->env, args[inst->a], &b) != napi_ok) [[unlikely]] {
270
+ ThrowError<Napi::TypeError>(call->env, "Unexpected %1 value, expected boolean", GetValueType(call->instance, args[inst->a]));
271
+ return call->env.Null();
272
+ }
273
+
274
+ *(bool *)(base + inst->b1) = b;
275
+
276
+ NEXT();
277
+ }
278
+ OP(PushInt8) { INTEGER(int8_t); NEXT(); }
279
+ OP(PushUInt8) { INTEGER(uint8_t); NEXT(); }
280
+ OP(PushInt16) { INTEGER(int16_t); NEXT(); }
281
+ OP(PushInt16S) { INTEGER_SWAP(int16_t); NEXT(); }
282
+ OP(PushUInt16) { INTEGER(uint16_t); NEXT(); }
283
+ OP(PushUInt16S) { INTEGER_SWAP(uint16_t); NEXT(); }
284
+ OP(PushInt32) { INTEGER(int32_t); NEXT(); }
285
+ OP(PushInt32S) { INTEGER_SWAP(int32_t); NEXT(); }
286
+ OP(PushUInt32) { INTEGER(uint32_t); NEXT(); }
287
+ OP(PushUInt32S) { INTEGER_SWAP(uint32_t); NEXT(); }
288
+ OP(PushInt64) { INTEGER(int64_t); NEXT(); }
289
+ OP(PushInt64S) { INTEGER_SWAP(int64_t); NEXT(); }
290
+ OP(PushUInt64) { INTEGER(uint64_t); NEXT(); }
291
+ OP(PushUInt64S) { INTEGER_SWAP(uint64_t); NEXT(); }
292
+ OP(PushString) {
293
+ const char *str;
294
+ if (!call->PushString(args[inst->a], inst->b2, &str)) [[unlikely]]
295
+ return call->env.Null();
296
+
297
+ *(const char **)(base + inst->b1) = str;
298
+
299
+ NEXT();
300
+ }
301
+ OP(PushString16) {
302
+ const char16_t *str16;
303
+ if (!call->PushString16(args[inst->a], inst->b2, &str16)) [[unlikely]]
304
+ return call->env.Null();
305
+
306
+ *(const char16_t **)(base + inst->b1) = str16;
307
+
308
+ NEXT();
309
+ }
310
+ OP(PushString32) {
311
+ const char32_t *str32;
312
+ if (!call->PushString32(args[inst->a], inst->b2, &str32)) [[unlikely]]
313
+ return call->env.Null();
314
+
315
+ *(const char32_t **)(base + inst->b1) = str32;
316
+
317
+ NEXT();
318
+ }
319
+ OP(PushPointer) {
320
+ void *ptr;
321
+ if (!call->PushPointer(args[inst->a], inst->type, inst->b2, &ptr)) [[unlikely]]
322
+ return call->env.Null();
323
+
324
+ *(void **)(base + inst->b1) = ptr;
325
+
326
+ NEXT();
327
+ }
328
+ OP(PushRecord) { K_UNREACHABLE(); return call->env.Null(); }
329
+ OP(PushUnion) { K_UNREACHABLE(); return call->env.Null(); }
330
+ OP(PushArray) { K_UNREACHABLE(); return call->env.Null(); }
331
+ OP(PushFloat32) {
332
+ float f;
333
+ if (!TryNumber(call->env, args[inst->a], &f)) [[unlikely]] {
334
+ ThrowError<Napi::TypeError>(call->env, "Unexpected %1 value, expected number", GetValueType(call->instance, args[inst->a]));
335
+ return call->env.Null();
336
+ }
337
+
338
+ memset(base + inst->b1, 0, 8);
339
+ memcpy(base + inst->b1, &f, 4);
340
+
341
+ NEXT();
342
+ }
343
+ OP(PushFloat64) {
344
+ double d;
345
+ if (!TryNumber(call->env, args[inst->a], &d)) [[unlikely]] {
346
+ ThrowError<Napi::TypeError>(call->env, "Unexpected %1 value, expected number", GetValueType(call->instance, args[inst->a]));
347
+ return call->env.Null();
348
+ }
349
+
350
+ *(double *)(base + inst->b1) = d;
351
+
352
+ NEXT();
353
+ }
354
+ OP(PushCallback) {
355
+ void *ptr;
356
+ if (!call->PushCallback(args[inst->a], inst->type, &ptr)) [[unlikely]]
357
+ return call->env.Null();
358
+
359
+ *(void **)(base + inst->b1) = ptr;
360
+
361
+ NEXT();
362
+ }
363
+ OP(PushPrototype) { K_UNREACHABLE(); return call->env.Null(); }
364
+ OP(PushAggregateReg) {
365
+ napi_value arg = args[inst->a];
366
+
367
+ if (!IsObject(call->env, arg)) [[unlikely]] {
368
+ ThrowError<Napi::TypeError>(call->env, "Unexpected %1 value, expected object", GetValueType(call->instance, arg));
369
+ return call->env.Null();
370
+ }
371
+
372
+ uint8_t *ptr = (uint8_t *)(base + inst->b1);
373
+
374
+ if (!call->PushObject(arg, inst->type, ptr))
375
+ return call->env.Null();
376
+
377
+ NEXT();
378
+ }
379
+ OP(PushAggregateStack) {
380
+ napi_value arg = args[inst->a];
381
+
382
+ if (!IsObject(call->env, arg)) [[unlikely]] {
383
+ ThrowError<Napi::TypeError>(call->env, "Unexpected %1 value, expected object", GetValueType(call->instance, arg));
384
+ return call->env.Null();
385
+ }
386
+
387
+ uint8_t *ptr = call->AllocHeap(inst->type->size);
388
+ *(uint8_t **)(base + inst->b1) = ptr;
389
+
390
+ if (!call->PushObject(arg, inst->type, ptr))
391
+ return call->env.Null();
392
+
393
+ NEXT();
394
+ }
395
+
396
+ #undef INTEGER_SWAP
397
+ #undef INTEGER
398
+
399
+ #define INTEGER(Suffix, CType) \
400
+ do { \
401
+ uint64_t rax = WRAP(ForwardCall ## Suffix(call->native, (uint8_t *)base, &call->saved_sp)); \
402
+ return NewInt(call->env, (CType)rax); \
403
+ } while (false)
404
+ #define INTEGER_SWAP(Suffix, CType) \
405
+ do { \
406
+ uint64_t rax = WRAP(ForwardCall ## Suffix(call->native, (uint8_t *)base, &call->saved_sp)); \
407
+ return NewInt(call->env, ReverseBytes((CType)rax)); \
408
+ } while (false)
409
+ #define DISPOSE(Ptr) \
410
+ do { \
411
+ if (inst->type->dispose) { \
412
+ inst->type->dispose(call->env, inst->type, (Ptr)); \
413
+ } \
414
+ } while (false)
415
+
416
+ OP(RunVoid) {
417
+ WRAP(ForwardCallG(call->native, (uint8_t *)base, &call->saved_sp));
418
+ return call->env.Undefined();
419
+ }
420
+ OP(RunBool) {
421
+ uint64_t rax = WRAP(ForwardCallG(call->native, (uint8_t *)base, &call->saved_sp));
422
+ return Napi::Boolean::New(call->env, rax & 0x1);
423
+ }
424
+ OP(RunInt8) { INTEGER(G, int8_t); }
425
+ OP(RunUInt8) { INTEGER(G, uint8_t); }
426
+ OP(RunInt16) { INTEGER(G, int16_t); }
427
+ OP(RunInt16S) { INTEGER_SWAP(G, int16_t); }
428
+ OP(RunUInt16) { INTEGER(G, uint16_t); }
429
+ OP(RunUInt16S) { INTEGER_SWAP(G, uint16_t); }
430
+ OP(RunInt32) { INTEGER(G, int32_t); }
431
+ OP(RunInt32S) { INTEGER_SWAP(G, int32_t); }
432
+ OP(RunUInt32) { INTEGER(G, uint32_t); }
433
+ OP(RunUInt32S) { INTEGER_SWAP(G, uint32_t); }
434
+ OP(RunInt64) { INTEGER(G, int64_t); }
435
+ OP(RunInt64S) { INTEGER_SWAP(G, int64_t); }
436
+ OP(RunUInt64) { INTEGER(G, uint64_t); }
437
+ OP(RunUInt64S) { INTEGER_SWAP(G, uint64_t); }
438
+ OP(RunString) {
439
+ uint64_t rax = WRAP(ForwardCallG(call->native, (uint8_t *)base, &call->saved_sp));
440
+ napi_value value = rax ? Napi::String::New(call->env, (const char *)rax) : call->env.Null();
441
+ DISPOSE((void *)rax);
442
+ return value;
443
+ }
444
+ OP(RunString16) {
445
+ uint64_t rax = WRAP(ForwardCallG(call->native, (uint8_t *)base, &call->saved_sp));
446
+ napi_value value = rax ? Napi::String::New(call->env, (const char16_t *)rax) : call->env.Null();
447
+ DISPOSE((void *)rax);
448
+ return value;
449
+ }
450
+ OP(RunString32) {
451
+ uint64_t rax = WRAP(ForwardCallG(call->native, (uint8_t *)base, &call->saved_sp));
452
+ napi_value value = rax ? MakeStringFromUTF32(call->env, (const char32_t *)rax) : call->env.Null();
453
+ DISPOSE((void *)rax);
454
+ return value;
455
+ }
456
+ OP(RunPointer) {
457
+ uint64_t rax = WRAP(ForwardCallG(call->native, (uint8_t *)base, &call->saved_sp));
458
+ napi_value value = rax ? WrapPointer(call->env, inst->type, (void *)rax) : call->env.Null();
459
+ DISPOSE((void *)rax);
460
+ return value;
461
+ }
462
+ OP(RunCallback) {
463
+ uint64_t rax = WRAP(ForwardCallG(call->native, (uint8_t *)base, &call->saved_sp));
464
+ return rax ? WrapCallback(call->env, inst->type, (void *)rax) : call->env.Null();
465
+ }
466
+ OP(RunRecord) { K_UNREACHABLE(); return call->env.Null(); }
467
+ OP(RunUnion) { K_UNREACHABLE(); return call->env.Null(); }
468
+ OP(RunArray) { K_UNREACHABLE(); return call->env.Null(); }
469
+ OP(RunFloat32) {
470
+ float f = WRAP(ForwardCallF(call->native, (uint8_t *)base, &call->saved_sp));
471
+ return Napi::Number::New(call->env, (double)f);
472
+ }
473
+ OP(RunFloat64) {
474
+ double d = WRAP(ForwardCallD(call->native, (uint8_t *)base, &call->saved_sp));
475
+ return Napi::Number::New(call->env, d);
476
+ }
477
+ OP(RunPrototype) { K_UNREACHABLE(); return call->env.Null(); }
478
+ OP(RunAggregateReg) {
479
+ auto ret = WRAP(ForwardCallG(call->native, (uint8_t *)base, &call->saved_sp));
480
+ return DecodeObject(call->env, (const uint8_t *)&ret, inst->type);
481
+ }
482
+ OP(RunAggregateStack) {
483
+ *(uint8_t **)base = call->AllocHeap(inst->a);
484
+ uint64_t rax = WRAP(ForwardCallG(call->native, (uint8_t *)base, &call->saved_sp));
485
+ return DecodeObject(call->env, (const uint8_t *)rax, inst->type);
486
+ }
487
+ OP(RunVoidX) {
488
+ WRAP(ForwardCallGX(call->native, (uint8_t *)base, &call->saved_sp));
489
+ return call->env.Undefined();
490
+ }
491
+ OP(RunBoolX) {
492
+ uint64_t rax = WRAP(ForwardCallGX(call->native, (uint8_t *)base, &call->saved_sp));
493
+ return Napi::Boolean::New(call->env, rax & 0x1);
494
+ }
495
+ OP(RunInt8X) { INTEGER(GX, int8_t); }
496
+ OP(RunUInt8X) { INTEGER(GX, uint8_t); }
497
+ OP(RunInt16X) { INTEGER(GX, int16_t); }
498
+ OP(RunInt16SX) { INTEGER_SWAP(GX, int16_t); }
499
+ OP(RunUInt16X) { INTEGER(GX, uint16_t); }
500
+ OP(RunUInt16SX) { INTEGER_SWAP(GX, uint16_t); }
501
+ OP(RunInt32X) { INTEGER(GX, int32_t); }
502
+ OP(RunInt32SX) { INTEGER_SWAP(GX, int32_t); }
503
+ OP(RunUInt32X) { INTEGER(GX, uint32_t); }
504
+ OP(RunUInt32SX) { INTEGER_SWAP(GX, uint32_t); }
505
+ OP(RunInt64X) { INTEGER(GX, int64_t); }
506
+ OP(RunInt64SX) { INTEGER_SWAP(GX, int64_t); }
507
+ OP(RunUInt64X) { INTEGER(GX, uint64_t); }
508
+ OP(RunUInt64SX) { INTEGER_SWAP(GX, uint64_t); }
509
+ OP(RunStringX) {
510
+ uint64_t rax = WRAP(ForwardCallGX(call->native, (uint8_t *)base, &call->saved_sp));
511
+ napi_value value = rax ? Napi::String::New(call->env, (const char *)rax) : call->env.Null();
512
+ DISPOSE((void *)rax);
513
+ return value;
514
+ }
515
+ OP(RunString16X) {
516
+ uint64_t rax = WRAP(ForwardCallGX(call->native, (uint8_t *)base, &call->saved_sp));
517
+ napi_value value = rax ? Napi::String::New(call->env, (const char16_t *)rax) : call->env.Null();
518
+ DISPOSE((void *)rax);
519
+ return value;
520
+ }
521
+ OP(RunString32X) {
522
+ uint64_t rax = WRAP(ForwardCallGX(call->native, (uint8_t *)base, &call->saved_sp));
523
+ napi_value value = rax ? MakeStringFromUTF32(call->env, (const char32_t *)rax) : call->env.Null();
524
+ DISPOSE((void *)rax);
525
+ return value;
526
+ }
527
+ OP(RunPointerX) {
528
+ uint64_t rax = WRAP(ForwardCallGX(call->native, (uint8_t *)base, &call->saved_sp));
529
+ napi_value value = rax ? WrapPointer(call->env, inst->type, (void *)rax) : call->env.Null();
530
+ DISPOSE((void *)rax);
531
+ return value;
532
+ }
533
+ OP(RunCallbackX) {
534
+ uint64_t rax = WRAP(ForwardCallGX(call->native, (uint8_t *)base, &call->saved_sp));
535
+ return rax ? WrapCallback(call->env, inst->type, (void *)rax) : call->env.Null();
536
+ }
537
+ OP(RunRecordX) { K_UNREACHABLE(); return call->env.Null(); }
538
+ OP(RunUnionX) { K_UNREACHABLE(); return call->env.Null(); }
539
+ OP(RunArrayX) { K_UNREACHABLE(); return call->env.Null(); }
540
+ OP(RunFloat32X) {
541
+ float f = WRAP(ForwardCallFX(call->native, (uint8_t *)base, &call->saved_sp));
542
+ return Napi::Number::New(call->env, (double)f);
543
+ }
544
+ OP(RunFloat64X) {
545
+ double d = WRAP(ForwardCallDX(call->native, (uint8_t *)base, &call->saved_sp));
546
+ return Napi::Number::New(call->env, d);
547
+ }
548
+ OP(RunPrototypeX) { K_UNREACHABLE(); return call->env.Null(); }
549
+ OP(RunAggregateRegX) {
550
+ auto ret = WRAP(ForwardCallGX(call->native, (uint8_t *)base, &call->saved_sp));
551
+ return DecodeObject(call->env, (const uint8_t *)&ret, inst->type);
552
+ }
553
+ OP(RunAggregateStackX) {
554
+ *(uint8_t **)base = call->AllocHeap(inst->a);
555
+ uint64_t rax = WRAP(ForwardCallGX(call->native, (uint8_t *)base, &call->saved_sp));
556
+ return DecodeObject(call->env, (const uint8_t *)rax, inst->type);
557
+ }
558
+
559
+ #undef DISPOSE
560
+ #undef INTEGER_SWAP
561
+ #undef INTEGER
562
+
563
+ #define CALL(Suffix) \
564
+ do { \
565
+ auto ret = WRAP(ForwardCall ## Suffix(call->native, (uint8_t *)base, &call->saved_sp)); \
566
+ memcpy(base, &ret, K_SIZE(ret)); \
567
+ } while (false)
568
+ #define DISPOSE() \
569
+ do { \
570
+ if (inst->type->dispose) { \
571
+ void *ptr = *(void **)base; \
572
+ inst->type->dispose(call->env, inst->type, ptr); \
573
+ } \
574
+ } while (false)
575
+ #define INTEGER(CType) \
576
+ do { \
577
+ uint64_t rax = *(uint64_t *)base; \
578
+ return NewInt(call->env, (CType)rax); \
579
+ } while (false)
580
+ #define INTEGER_SWAP(CType) \
581
+ do { \
582
+ uint64_t rax = *(uint64_t *)base; \
583
+ return NewInt(call->env, ReverseBytes((CType)rax)); \
584
+ } while (false)
585
+
586
+ OP(Yield) {
587
+ call->async_ip = inst + 1;
588
+ return call->env.Null();
589
+ }
590
+
591
+ OP(CallG) { CALL(G); return call->env.Null(); }
592
+ OP(CallF) { CALL(F); return call->env.Null(); }
593
+ OP(CallD) { CALL(D); return call->env.Null(); }
594
+ OP(CallStack) {
595
+ *(uint8_t **)base = call->AllocHeap(inst->a);
596
+ CALL(G);
597
+ return call->env.Null();
598
+ }
599
+ OP(CallGX) { CALL(GX); return call->env.Null(); }
600
+ OP(CallFX) { CALL(FX); return call->env.Null(); }
601
+ OP(CallDX) { CALL(DX); return call->env.Null(); }
602
+ OP(CallStackX) {
603
+ *(uint8_t **)base = call->AllocHeap(inst->a);
604
+ CALL(GX);
605
+ return call->env.Null();
606
+ }
607
+
608
+ OP(ReturnVoid) { return call->env.Undefined(); }
609
+ OP(ReturnBool) {
610
+ uint64_t rax = *(uint64_t *)base;
611
+ return Napi::Boolean::New(call->env, rax & 0x1);
612
+ }
613
+ OP(ReturnInt8) { INTEGER(int8_t); }
614
+ OP(ReturnUInt8) { INTEGER(uint8_t); }
615
+ OP(ReturnInt16) { INTEGER(int16_t); }
616
+ OP(ReturnInt16S) { INTEGER_SWAP(int16_t); }
617
+ OP(ReturnUInt16) { INTEGER(uint16_t); }
618
+ OP(ReturnUInt16S) { INTEGER_SWAP(uint16_t); }
619
+ OP(ReturnInt32) { INTEGER(int32_t); }
620
+ OP(ReturnInt32S) { INTEGER_SWAP(int32_t); }
621
+ OP(ReturnUInt32) { INTEGER(uint32_t); }
622
+ OP(ReturnUInt32S) { INTEGER_SWAP(uint32_t); }
623
+ OP(ReturnInt64) { INTEGER(int64_t); }
624
+ OP(ReturnInt64S) { INTEGER_SWAP(int64_t); }
625
+ OP(ReturnUInt64) { INTEGER(uint64_t); }
626
+ OP(ReturnUInt64S) { INTEGER_SWAP(uint64_t); }
627
+ OP(ReturnString) {
628
+ uint64_t rax = *(uint64_t *)base;
629
+ napi_value value = rax ? Napi::String::New(call->env, (const char *)rax) : call->env.Null();
630
+ DISPOSE();
631
+ return value;
632
+ }
633
+ OP(ReturnString16) {
634
+ uint64_t rax = *(uint64_t *)base;
635
+ napi_value value = rax ? Napi::String::New(call->env, (const char16_t *)rax) : call->env.Null();
636
+ DISPOSE();
637
+ return value;
638
+ }
639
+ OP(ReturnString32) {
640
+ uint64_t rax = *(uint64_t *)base;
641
+ napi_value value = rax ? MakeStringFromUTF32(call->env, (const char32_t *)rax) : call->env.Null();
642
+ DISPOSE();
643
+ return value;
644
+ }
645
+ OP(ReturnPointer) {
646
+ uint64_t rax = *(uint64_t *)base;
647
+ napi_value value = rax ? WrapPointer(call->env, inst->type, (void *)rax) : call->env.Null();
648
+ DISPOSE();
649
+ return value;
650
+ }
651
+ OP(ReturnCallback) {
652
+ uint64_t rax = *(uint64_t *)base;
653
+ return rax ? WrapCallback(call->env, inst->type, (void *)rax) : call->env.Null();
654
+ }
655
+ OP(ReturnRecord) { K_UNREACHABLE(); return call->env.Null(); }
656
+ OP(ReturnUnion) { K_UNREACHABLE(); return call->env.Null(); }
657
+ OP(ReturnArray) { K_UNREACHABLE(); return call->env.Null(); }
658
+ OP(ReturnFloat32) {
659
+ float f = *(float *)base;
660
+ return Napi::Number::New(call->env, (double)f);
661
+ }
662
+ OP(ReturnFloat64) {
663
+ double d = *(double *)base;
664
+ return Napi::Number::New(call->env, d);
665
+ }
666
+ OP(ReturnPrototype) { K_UNREACHABLE(); return call->env.Null(); }
667
+ OP(ReturnAggregate) {
668
+ uint64_t rax = *(uint64_t *)base;
669
+ return DecodeObject(call->env, (const uint8_t *)rax, inst->type);
670
+ }
671
+
672
+ #undef INTEGER_SWAP
673
+ #undef INTEGER
674
+ #undef DISPOSE
675
+ #undef CALL
676
+
677
+ #if defined(MUST_TAIL)
678
+ ForwardFunc *const ForwardDispatch[256] = {
679
+ #define PRIMITIVE(Name) HandlePush ## Name,
680
+ #include "../primitives.inc"
681
+ HandlePushAggregateReg,
682
+ HandlePushAggregateStack,
683
+ #define PRIMITIVE(Name) HandleRun ## Name,
684
+ #include "../primitives.inc"
685
+ HandleRunAggregateReg,
686
+ HandleRunAggregateStack,
687
+ #define PRIMITIVE(Name) HandleRun ## Name ## X,
688
+ #include "../primitives.inc"
689
+ HandleRunAggregateRegX,
690
+ HandleRunAggregateStackX,
691
+ HandleYield,
692
+ HandleCallG,
693
+ HandleCallF,
694
+ HandleCallD,
695
+ HandleCallStack,
696
+ HandleCallGX,
697
+ HandleCallFX,
698
+ HandleCallDX,
699
+ HandleCallStackX,
700
+ #define PRIMITIVE(Name) HandleReturn ## Name,
701
+ #include "../primitives.inc"
702
+ HandleReturnAggregate
703
+ };
704
+
705
+ FORCE_INLINE napi_value RunLoop(CallData *call, napi_value *args, uint64_t *base, const AbiInstruction *inst)
706
+ {
707
+ return ((ForwardFunc *)inst->op)(call, args, base, inst);
708
+ }
709
+ #else
710
+ }
711
+ }
712
+
713
+ K_UNREACHABLE();
714
+ }
715
+ #endif
716
+
717
+ #undef WRAP
718
+
719
+ #undef NEXT
720
+ #undef OP
721
+ }
722
+
723
+ #if defined(__GNUC__) || defined(__clang__)
724
+ #pragma GCC diagnostic pop
725
+ #endif
726
+
727
+ napi_value CallData::Run(const FunctionInfo *func, napi_value *args)
728
+ {
729
+ uint8_t *base = AllocStack<uint8_t>(func->stk_size);
730
+ if (!base) [[unlikely]]
731
+ return env.Null();
732
+
733
+ const AbiInstruction *first = func->sync.ptr;
734
+ return RunLoop(this, args, (uint64_t *)base, first);
735
+ }
736
+
737
+ bool CallData::PrepareAsync(const FunctionInfo *func, napi_value *args)
738
+ {
739
+ uint8_t *base = AllocStack<uint8_t>(func->stk_size);
740
+ if (!base) [[unlikely]]
741
+ return env.Null();
742
+ async_base = base;
743
+
744
+ const AbiInstruction *first = func->async.ptr;
745
+ return RunLoop(this, args, (uint64_t *)base, first);
746
+ }
747
+
748
+ void CallData::ExecuteAsync()
749
+ {
750
+ const AbiInstruction *next = async_ip++;
751
+ RunLoop(this, nullptr, (uint64_t *)async_base, next);
752
+ }
753
+
754
+ napi_value CallData::EndAsync()
755
+ {
756
+ const AbiInstruction *next = async_ip++;
757
+ return RunLoop(this, nullptr, (uint64_t *)async_base, next);
758
+ }
759
+
760
+ void CallData::Relay(Size idx, uint8_t *sp)
761
+ {
762
+ TrampolineInfo *trampoline = &shared.trampolines[idx];
763
+
764
+ uint8_t *own_sp = sp;
765
+ uint8_t *caller_sp = sp + 128;
766
+ BackRegisters *out_reg = (BackRegisters *)(sp + 64);
767
+
768
+ const FunctionInfo *proto = trampoline->proto;
769
+ Napi::Function func = trampoline->func.Value();
770
+
771
+ uint64_t *gpr_ptr = (uint64_t *)own_sp;
772
+ uint64_t *xmm_ptr = gpr_ptr + 4;
773
+ uint64_t *stk_ptr = (uint64_t *)caller_sp;
774
+
775
+ uint8_t *return_ptr = !proto->ret.regular ? (uint8_t *)gpr_ptr[0] : nullptr;
776
+
777
+ K_DEFER_N(err_guard) {
778
+ trampoline->state = -1;
779
+ memset(out_reg, 0, K_SIZE(*out_reg));
780
+ };
781
+
782
+ LocalArray<napi_value, MaxParameters + 1> arguments;
783
+
784
+ arguments.Append(!trampoline->recv.IsEmpty() ? trampoline->recv.Value() : env.Undefined());
785
+
786
+ // Convert to JS arguments
787
+ for (Size i = 0, j = !!return_ptr; i < proto->parameters.len; i++, j++) {
788
+ const ParameterInfo &param = proto->parameters[i];
789
+ K_ASSERT(param.directions >= 1 && param.directions <= 3);
790
+
791
+ switch (param.type->primitive) {
792
+ case PrimitiveKind::Void: { K_UNREACHABLE(); } break;
793
+
794
+ case PrimitiveKind::Bool: {
795
+ bool b = *(bool *)(j < 4 ? gpr_ptr + j : stk_ptr);
796
+ stk_ptr += (j >= 4);
797
+
798
+ Napi::Value arg = Napi::Boolean::New(env, b);
799
+ arguments.Append(arg);
800
+ } break;
801
+ case PrimitiveKind::Int8: {
802
+ int8_t v = *(int8_t *)(j < 4 ? gpr_ptr + j : stk_ptr);
803
+ stk_ptr += (j >= 4);
804
+
805
+ Napi::Value arg = NewInt(env, v);
806
+ arguments.Append(arg);
807
+ } break;
808
+ case PrimitiveKind::UInt8: {
809
+ uint8_t v = *(uint8_t *)(j < 4 ? gpr_ptr + j : stk_ptr);
810
+ stk_ptr += (j >= 4);
811
+
812
+ Napi::Value arg = NewInt(env, v);
813
+ arguments.Append(arg);
814
+ } break;
815
+ case PrimitiveKind::Int16: {
816
+ int16_t v = *(int16_t *)(j < 4 ? gpr_ptr + j : stk_ptr);
817
+ stk_ptr += (j >= 4);
818
+
819
+ Napi::Value arg = NewInt(env, v);
820
+ arguments.Append(arg);
821
+ } break;
822
+ case PrimitiveKind::Int16S: {
823
+ int16_t v = *(int16_t *)(j < 4 ? gpr_ptr + j : stk_ptr);
824
+ stk_ptr += (j >= 4);
825
+
826
+ Napi::Value arg = NewInt(env, ReverseBytes(v));
827
+ arguments.Append(arg);
828
+ } break;
829
+ case PrimitiveKind::UInt16: {
830
+ uint16_t v = *(uint16_t *)(j < 4 ? gpr_ptr + j : stk_ptr);
831
+ stk_ptr += (j >= 4);
832
+
833
+ Napi::Value arg = NewInt(env, v);
834
+ arguments.Append(arg);
835
+ } break;
836
+ case PrimitiveKind::UInt16S: {
837
+ uint16_t v = *(uint16_t *)(j < 4 ? gpr_ptr + j : stk_ptr);
838
+ stk_ptr += (j >= 4);
839
+
840
+ Napi::Value arg = NewInt(env, ReverseBytes(v));
841
+ arguments.Append(arg);
842
+ } break;
843
+ case PrimitiveKind::Int32: {
844
+ int32_t v = *(int32_t *)(j < 4 ? gpr_ptr + j : stk_ptr);
845
+ stk_ptr += (j >= 4);
846
+
847
+ Napi::Value arg = NewInt(env, v);
848
+ arguments.Append(arg);
849
+ } break;
850
+ case PrimitiveKind::Int32S: {
851
+ int32_t v = *(int32_t *)(j < 4 ? gpr_ptr + j : stk_ptr);
852
+ stk_ptr += (j >= 4);
853
+
854
+ Napi::Value arg = NewInt(env, ReverseBytes(v));
855
+ arguments.Append(arg);
856
+ } break;
857
+ case PrimitiveKind::UInt32: {
858
+ uint32_t v = *(uint32_t *)(j < 4 ? gpr_ptr + j : stk_ptr);
859
+ stk_ptr += (j >= 4);
860
+
861
+ Napi::Value arg = NewInt(env, v);
862
+ arguments.Append(arg);
863
+ } break;
864
+ case PrimitiveKind::UInt32S: {
865
+ uint32_t v = *(uint32_t *)(j < 4 ? gpr_ptr + j : stk_ptr);
866
+ stk_ptr += (j >= 4);
867
+
868
+ Napi::Value arg = NewInt(env, ReverseBytes(v));
869
+ arguments.Append(arg);
870
+ } break;
871
+ case PrimitiveKind::Int64: {
872
+ int64_t v = *(int64_t *)(j < 4 ? gpr_ptr + j : stk_ptr);
873
+ stk_ptr += (j >= 4);
874
+
875
+ Napi::Value arg = NewInt(env, v);
876
+ arguments.Append(arg);
877
+ } break;
878
+ case PrimitiveKind::Int64S: {
879
+ int64_t v = *(int64_t *)(j < 4 ? gpr_ptr + j : stk_ptr);
880
+ stk_ptr += (j >= 4);
881
+
882
+ Napi::Value arg = NewInt(env, ReverseBytes(v));
883
+ arguments.Append(arg);
884
+ } break;
885
+ case PrimitiveKind::UInt64: {
886
+ uint64_t v = *(uint64_t *)(j < 4 ? gpr_ptr + j : stk_ptr);
887
+ stk_ptr += (j >= 4);
888
+
889
+ Napi::Value arg = NewInt(env, v);
890
+ arguments.Append(arg);
891
+ } break;
892
+ case PrimitiveKind::UInt64S: {
893
+ uint64_t v = *(uint64_t *)(j < 4 ? gpr_ptr + j : stk_ptr);
894
+ stk_ptr += (j >= 4);
895
+
896
+ Napi::Value arg = NewInt(env, ReverseBytes(v));
897
+ arguments.Append(arg);
898
+ } break;
899
+ case PrimitiveKind::String: {
900
+ const char *str = *(const char **)(j < 4 ? gpr_ptr + j : stk_ptr);
901
+ stk_ptr += (j >= 4);
902
+
903
+ Napi::Value arg = str ? Napi::String::New(env, str) : env.Null();
904
+ arguments.Append(arg);
905
+
906
+ if (param.type->dispose) {
907
+ param.type->dispose(env, param.type, str);
908
+ }
909
+ } break;
910
+ case PrimitiveKind::String16: {
911
+ const char16_t *str16 = *(const char16_t **)(j < 4 ? gpr_ptr + j : stk_ptr);
912
+ stk_ptr += (j >= 4);
913
+
914
+ Napi::Value arg = str16 ? Napi::String::New(env, str16) : env.Null();
915
+ arguments.Append(arg);
916
+
917
+ if (param.type->dispose) {
918
+ param.type->dispose(env, param.type, str16);
919
+ }
920
+ } break;
921
+ case PrimitiveKind::String32: {
922
+ const char32_t *str32 = *(const char32_t **)(j < 4 ? gpr_ptr + j : stk_ptr);
923
+ stk_ptr += (j >= 4);
924
+
925
+ Napi::Value arg = str32 ? MakeStringFromUTF32(env, str32) : env.Null();
926
+ arguments.Append(arg);
927
+ } break;
928
+ case PrimitiveKind::Pointer: {
929
+ void *ptr2 = *(void **)(j < 4 ? gpr_ptr + j : stk_ptr);
930
+ stk_ptr += (j >= 4);
931
+
932
+ Napi::Value p = ptr2 ? WrapPointer(env, param.type->ref.type, ptr2) : env.Null();
933
+ arguments.Append(p);
934
+
935
+ if (param.type->dispose) {
936
+ param.type->dispose(env, param.type, ptr2);
937
+ }
938
+ } break;
939
+ case PrimitiveKind::Callback: {
940
+ void *ptr2 = *(void **)(j < 4 ? gpr_ptr + j : stk_ptr);
941
+ stk_ptr += (j >= 4);
942
+
943
+ Napi::Value p = ptr2 ? WrapCallback(env, param.type->ref.type, ptr2) : env.Null();
944
+ arguments.Append(p);
945
+
946
+ if (param.type->dispose) {
947
+ param.type->dispose(env, param.type, ptr2);
948
+ }
949
+ } break;
950
+ case PrimitiveKind::Record:
951
+ case PrimitiveKind::Union: {
952
+ uint8_t *ptr;
953
+ if (param.regular) {
954
+ ptr = (uint8_t *)(j < 4 ? gpr_ptr + j : stk_ptr);
955
+ } else {
956
+ ptr = *(uint8_t **)(j < 4 ? gpr_ptr + j : stk_ptr);
957
+ }
958
+ stk_ptr += (j >= 4);
959
+
960
+ Napi::Object obj2 = DecodeObject(env, ptr, param.type);
961
+ arguments.Append(obj2);
962
+ } break;
963
+ case PrimitiveKind::Array: { K_UNREACHABLE(); } break;
964
+ case PrimitiveKind::Float32: {
965
+ float f = *(float *)(j < 4 ? xmm_ptr + j : stk_ptr);
966
+ stk_ptr += (j >= 4);
967
+
968
+ Napi::Value arg = Napi::Number::New(env, (double)f);
969
+ arguments.Append(arg);
970
+ } break;
971
+ case PrimitiveKind::Float64: {
972
+ double d = *(double *)(j < 4 ? xmm_ptr + j : stk_ptr);
973
+ stk_ptr += (j >= 4);
974
+
975
+ Napi::Value arg = Napi::Number::New(env, d);
976
+ arguments.Append(arg);
977
+ } break;
978
+
979
+ case PrimitiveKind::Prototype: { K_UNREACHABLE(); } break;
980
+ }
981
+ }
982
+
983
+ const TypeInfo *type = proto->ret.type;
984
+
985
+ // Make the call!
986
+ Napi::Value value = func.Call(arguments[0], arguments.len - 1, arguments.data + 1);
987
+
988
+ if (env.IsExceptionPending()) [[unlikely]]
989
+ return;
990
+
991
+ #define RETURN_INTEGER(CType) \
992
+ do { \
993
+ CType v; \
994
+ if (!TryNumber(env, value, &v)) [[unlikely]] { \
995
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
996
+ return; \
997
+ } \
998
+ \
999
+ out_reg->rax = (uint64_t)v; \
1000
+ } while (false)
1001
+ #define RETURN_INTEGER_SWAP(CType) \
1002
+ do { \
1003
+ CType v; \
1004
+ if (!TryNumber(env, value, &v)) [[unlikely]] { \
1005
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value)); \
1006
+ return; \
1007
+ } \
1008
+ \
1009
+ out_reg->rax = (uint64_t)ReverseBytes(v); \
1010
+ } while (false)
1011
+
1012
+ switch (type->primitive) {
1013
+ case PrimitiveKind::Void: {} break;
1014
+ case PrimitiveKind::Bool: {
1015
+ bool b;
1016
+ if (napi_get_value_bool(env, value, &b) != napi_ok) [[unlikely]] {
1017
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected boolean", GetValueType(instance, value));
1018
+ return;
1019
+ }
1020
+
1021
+ out_reg->rax = (uint64_t)b;
1022
+ } break;
1023
+ case PrimitiveKind::Int8: { RETURN_INTEGER(int8_t); } break;
1024
+ case PrimitiveKind::UInt8: { RETURN_INTEGER(uint8_t); } break;
1025
+ case PrimitiveKind::Int16: { RETURN_INTEGER(int16_t); } break;
1026
+ case PrimitiveKind::Int16S: { RETURN_INTEGER_SWAP(int16_t); } break;
1027
+ case PrimitiveKind::UInt16: { RETURN_INTEGER(uint16_t); } break;
1028
+ case PrimitiveKind::UInt16S: { RETURN_INTEGER_SWAP(uint16_t); } break;
1029
+ case PrimitiveKind::Int32: { RETURN_INTEGER(int32_t); } break;
1030
+ case PrimitiveKind::Int32S: { RETURN_INTEGER_SWAP(int32_t); } break;
1031
+ case PrimitiveKind::UInt32: { RETURN_INTEGER(uint32_t); } break;
1032
+ case PrimitiveKind::UInt32S: { RETURN_INTEGER_SWAP(uint32_t); } break;
1033
+ case PrimitiveKind::Int64: { RETURN_INTEGER(int64_t); } break;
1034
+ case PrimitiveKind::Int64S: { RETURN_INTEGER_SWAP(int64_t); } break;
1035
+ case PrimitiveKind::UInt64: { RETURN_INTEGER(uint64_t); } break;
1036
+ case PrimitiveKind::UInt64S: { RETURN_INTEGER_SWAP(uint64_t); } break;
1037
+ case PrimitiveKind::String: {
1038
+ const char *str;
1039
+ if (!PushString(value, 1, &str)) [[unlikely]]
1040
+ return;
1041
+
1042
+ out_reg->rax = (uint64_t)str;
1043
+ } break;
1044
+ case PrimitiveKind::String16: {
1045
+ const char16_t *str16;
1046
+ if (!PushString16(value, 1, &str16)) [[unlikely]]
1047
+ return;
1048
+
1049
+ out_reg->rax = (uint64_t)str16;
1050
+ } break;
1051
+ case PrimitiveKind::String32: {
1052
+ const char32_t *str32;
1053
+ if (!PushString32(value, 1, &str32)) [[unlikely]]
1054
+ return;
1055
+
1056
+ out_reg->rax = (uint64_t)str32;
1057
+ } break;
1058
+ case PrimitiveKind::Pointer: {
1059
+ void *ptr;
1060
+ if (!PushPointer(value, type, 1, &ptr)) [[unlikely]]
1061
+ return;
1062
+
1063
+ out_reg->rax = (uint64_t)ptr;
1064
+ } break;
1065
+ case PrimitiveKind::Record:
1066
+ case PrimitiveKind::Union: {
1067
+ if (!IsObject(env, value)) [[unlikely]] {
1068
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
1069
+ return;
1070
+ }
1071
+
1072
+ Napi::Object obj = value.As<Napi::Object>();
1073
+
1074
+ if (return_ptr) {
1075
+ if (!PushObject(obj, type, return_ptr))
1076
+ return;
1077
+ out_reg->rax = (uint64_t)return_ptr;
1078
+ } else {
1079
+ PushObject(obj, type, (uint8_t *)&out_reg->rax);
1080
+ }
1081
+ } break;
1082
+ case PrimitiveKind::Array: { K_UNREACHABLE(); } break;
1083
+ case PrimitiveKind::Float32: {
1084
+ float f;
1085
+ if (!TryNumber(env, value, &f)) [[unlikely]] {
1086
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
1087
+ return;
1088
+ }
1089
+
1090
+ memset(&out_reg->xmm0, 0, 8);
1091
+ memcpy(&out_reg->xmm0, &f, 4);
1092
+ } break;
1093
+ case PrimitiveKind::Float64: {
1094
+ double d;
1095
+ if (!TryNumber(env, value, &d)) [[unlikely]] {
1096
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
1097
+ return;
1098
+ }
1099
+
1100
+ out_reg->xmm0 = d;
1101
+ } break;
1102
+ case PrimitiveKind::Callback: {
1103
+ void *ptr;
1104
+ if (!PushCallback(value, type, &ptr)) [[unlikely]]
1105
+ return;
1106
+
1107
+ out_reg->rax = (uint64_t)ptr;
1108
+ } break;
1109
+
1110
+ case PrimitiveKind::Prototype: { K_UNREACHABLE(); } break;
1111
+ }
1112
+
1113
+ #undef RETURN_INTEGER_SWAP
1114
+ #undef RETURN_INTEGER
1115
+
1116
+ err_guard.Disable();
1117
+ }
1118
+
1119
+ }
1120
+
1121
+ #endif