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