koffi 1.1.1 → 1.1.4

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 (53) hide show
  1. package/CMakeLists.txt +13 -7
  2. package/README.md +15 -26
  3. package/build/qemu/1.1.4/koffi_darwin_x64.tar.gz +0 -0
  4. package/build/qemu/1.1.4/koffi_freebsd_arm64.tar.gz +0 -0
  5. package/build/qemu/1.1.4/koffi_freebsd_ia32.tar.gz +0 -0
  6. package/build/qemu/1.1.4/koffi_freebsd_x64.tar.gz +0 -0
  7. package/build/qemu/1.1.4/koffi_linux_arm.tar.gz +0 -0
  8. package/build/qemu/1.1.4/koffi_linux_arm64.tar.gz +0 -0
  9. package/build/qemu/1.1.4/koffi_linux_ia32.tar.gz +0 -0
  10. package/build/qemu/1.1.4/koffi_linux_riscv64.tar.gz +0 -0
  11. package/build/qemu/1.1.4/koffi_linux_x64.tar.gz +0 -0
  12. package/build/qemu/1.1.4/koffi_openbsd_ia32.tar.gz +0 -0
  13. package/build/qemu/1.1.4/koffi_openbsd_x64.tar.gz +0 -0
  14. package/build/qemu/1.1.4/koffi_win32_ia32.tar.gz +0 -0
  15. package/build/qemu/1.1.4/koffi_win32_x64.tar.gz +0 -0
  16. package/package.json +2 -2
  17. package/qemu/qemu.js +13 -10
  18. package/qemu/registry/machines.json +138 -3
  19. package/qemu/registry/sha256sum.txt +27 -12
  20. package/src/abi_arm32.cc +29 -16
  21. package/src/abi_arm64.cc +33 -17
  22. package/src/abi_riscv64.cc +468 -0
  23. package/src/abi_riscv64_fwd.S +129 -0
  24. package/src/abi_x64_sysv.cc +9 -10
  25. package/src/abi_x64_win.cc +5 -8
  26. package/src/abi_x86.cc +11 -6
  27. package/src/call.cc +24 -36
  28. package/src/call.hh +14 -24
  29. package/src/ffi.cc +75 -27
  30. package/src/ffi.hh +13 -5
  31. package/src/parser.cc +48 -26
  32. package/src/parser.hh +3 -1
  33. package/src/util.cc +26 -57
  34. package/src/util.hh +17 -1
  35. package/test/CMakeLists.txt +3 -0
  36. package/test/misc.c +34 -0
  37. package/vendor/_patches/glfw_001_fix_openbsd_xlib_soname.patch +145 -0
  38. package/vendor/libcc/libcc.cc +7 -7
  39. package/vendor/libcc/libcc.hh +8 -2
  40. package/vendor/raylib/src/external/glfw/src/egl_context.c +6 -0
  41. package/vendor/raylib/src/external/glfw/src/osmesa_context.c +2 -0
  42. package/vendor/raylib/src/external/glfw/src/vulkan.c +2 -0
  43. package/vendor/raylib/src/external/glfw/src/x11_init.c +20 -0
  44. package/build/qemu/1.1.1/koffi_darwin_x64.tar.gz +0 -0
  45. package/build/qemu/1.1.1/koffi_freebsd_arm64.tar.gz +0 -0
  46. package/build/qemu/1.1.1/koffi_freebsd_ia32.tar.gz +0 -0
  47. package/build/qemu/1.1.1/koffi_freebsd_x64.tar.gz +0 -0
  48. package/build/qemu/1.1.1/koffi_linux_arm.tar.gz +0 -0
  49. package/build/qemu/1.1.1/koffi_linux_arm64.tar.gz +0 -0
  50. package/build/qemu/1.1.1/koffi_linux_ia32.tar.gz +0 -0
  51. package/build/qemu/1.1.1/koffi_linux_x64.tar.gz +0 -0
  52. package/build/qemu/1.1.1/koffi_win32_ia32.tar.gz +0 -0
  53. package/build/qemu/1.1.1/koffi_win32_x64.tar.gz +0 -0
@@ -0,0 +1,468 @@
1
+ // This program is free software: you can redistribute it and/or modify
2
+ // it under the terms of the GNU Affero General Public License as published by
3
+ // the Free Software Foundation, either version 3 of the License, or
4
+ // (at your option) any later version.
5
+ //
6
+ // This program is distributed in the hope that it will be useful,
7
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
8
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9
+ // GNU Affero General Public License for more details.
10
+ //
11
+ // You should have received a copy of the GNU Affero General Public License
12
+ // along with this program. If not, see https://www.gnu.org/licenses/.
13
+
14
+ #if __riscv_xlen == 64
15
+
16
+ #include "vendor/libcc/libcc.hh"
17
+ #include "ffi.hh"
18
+ #include "call.hh"
19
+ #include "util.hh"
20
+
21
+ #include <napi.h>
22
+
23
+ namespace RG {
24
+
25
+ struct A0A1Ret {
26
+ uint64_t a0;
27
+ uint64_t a1;
28
+ };
29
+ struct A0Fa0Ret {
30
+ uint64_t a0;
31
+ double fa0;
32
+ };
33
+ struct Fa0A0Ret {
34
+ double fa0;
35
+ uint64_t a0;
36
+ };
37
+ struct Fa0Fa1Ret {
38
+ double fa0;
39
+ double fa1;
40
+ };
41
+
42
+ extern "C" A0A1Ret ForwardCallGG(const void *func, uint8_t *sp);
43
+ extern "C" float ForwardCallF(const void *func, uint8_t *sp);
44
+ extern "C" Fa0A0Ret ForwardCallDG(const void *func, uint8_t *sp);
45
+ extern "C" A0Fa0Ret ForwardCallGD(const void *func, uint8_t *sp);
46
+ extern "C" Fa0Fa1Ret ForwardCallDD(const void *func, uint8_t *sp);
47
+
48
+ extern "C" A0A1Ret ForwardCallXGG(const void *func, uint8_t *sp);
49
+ extern "C" float ForwardCallXF(const void *func, uint8_t *sp);
50
+ extern "C" Fa0A0Ret ForwardCallXDG(const void *func, uint8_t *sp);
51
+ extern "C" A0Fa0Ret ForwardCallXGD(const void *func, uint8_t *sp);
52
+ extern "C" Fa0Fa1Ret ForwardCallXDD(const void *func, uint8_t *sp);
53
+
54
+ static void AnalyseParameter(ParameterInfo *param, int gpr_avail, int vec_avail)
55
+ {
56
+ gpr_avail = std::min(2, gpr_avail);
57
+ vec_avail = std::min(2, vec_avail);
58
+
59
+ if (param->type->size > 16) {
60
+ param->gpr_count = gpr_avail ? 1 : 0;
61
+ param->use_memory = true;
62
+
63
+ return;
64
+ }
65
+
66
+ int gpr_count = 0;
67
+ int vec_count = 0;
68
+ bool gpr_first = false;
69
+
70
+ AnalyseFlat(param->type, [&](const TypeInfo *type, int offset, int count) {
71
+ #if defined(__riscv_float_abi_double)
72
+ bool fp = IsFloat(type);
73
+ #elif defined(__riscv_float_abi_soft)
74
+ bool fp = false;
75
+ #else
76
+ #error The RISC-V single-precision float ABI (LP64F) is not supported
77
+ #endif
78
+
79
+ if (fp) {
80
+ vec_count += count;
81
+ } else {
82
+ gpr_count += count;
83
+ gpr_first |= !vec_count;
84
+ }
85
+ });
86
+
87
+ if (gpr_count == 1 && vec_count == 1 && gpr_avail && vec_avail) {
88
+ param->gpr_count = 1;
89
+ param->vec_count = 1;
90
+ param->gpr_first = gpr_first;
91
+ } else if (vec_count && !gpr_count && vec_count <= vec_avail) {
92
+ param->vec_count = vec_count;
93
+ } else if (gpr_avail) {
94
+ param->gpr_count = (param->type->size + 7) / 8;
95
+ param->gpr_first = true;
96
+ }
97
+ }
98
+
99
+ bool AnalyseFunction(InstanceData *, FunctionInfo *func)
100
+ {
101
+ AnalyseParameter(&func->ret, 2, 2);
102
+
103
+ int gpr_avail = 8 - func->ret.use_memory;
104
+ int vec_avail = 8;
105
+
106
+ for (ParameterInfo &param: func->parameters) {
107
+ AnalyseParameter(&param, gpr_avail, !param.variadic ? vec_avail : 0);
108
+
109
+ gpr_avail = std::max(0, gpr_avail - param.gpr_count);
110
+ vec_avail = std::max(0, vec_avail - param.vec_count);
111
+ }
112
+
113
+ func->args_size = 8 * func->parameters.len;
114
+ func->forward_fp = (vec_avail < 8);
115
+
116
+ return true;
117
+ }
118
+
119
+ bool CallData::Prepare(const Napi::CallbackInfo &info)
120
+ {
121
+ uint8_t *args_ptr = nullptr;
122
+ uint64_t *gpr_ptr = nullptr;
123
+ uint64_t *vec_ptr = nullptr;
124
+
125
+ // Return through registers unless it's too big
126
+ if (RG_UNLIKELY(!AllocStack(func->args_size, 16, &args_ptr)))
127
+ return false;
128
+ if (RG_UNLIKELY(!AllocStack(8 * 8, 8, &gpr_ptr)))
129
+ return false;
130
+ if (RG_UNLIKELY(!AllocStack(8 * 8, 8, &vec_ptr)))
131
+ return false;
132
+ if (func->ret.use_memory) {
133
+ if (RG_UNLIKELY(!AllocHeap(func->ret.type->size, 16, &return_ptr)))
134
+ return false;
135
+ *(uint8_t **)(gpr_ptr++) = return_ptr;
136
+ }
137
+
138
+ // Push arguments
139
+ for (Size i = 0; i < func->parameters.len; i++) {
140
+ const ParameterInfo &param = func->parameters[i];
141
+ RG_ASSERT(param.directions >= 1 && param.directions <= 3);
142
+
143
+ Napi::Value value = info[param.offset];
144
+
145
+ switch (param.type->primitive) {
146
+ case PrimitiveKind::Void: { RG_UNREACHABLE(); } break;
147
+
148
+ case PrimitiveKind::Bool: {
149
+ if (RG_UNLIKELY(!value.IsBoolean())) {
150
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected boolean", GetValueType(instance, value), i + 1);
151
+ return false;
152
+ }
153
+
154
+ bool b = value.As<Napi::Boolean>();
155
+
156
+ if (RG_LIKELY(param.gpr_count)) {
157
+ *(gpr_ptr++) = (uint64_t)b;
158
+ } else {
159
+ *(uint64_t *)args_ptr = (uint64_t)b;
160
+ args_ptr += 8;
161
+ }
162
+ } break;
163
+ case PrimitiveKind::Int8:
164
+ case PrimitiveKind::Int16:
165
+ case PrimitiveKind::Int32:
166
+ case PrimitiveKind::Int64: {
167
+ if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
168
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
169
+ return false;
170
+ }
171
+
172
+ int64_t v = CopyNumber<int64_t>(value);
173
+
174
+ if (RG_LIKELY(param.gpr_count)) {
175
+ *(int64_t *)(gpr_ptr++) = v;
176
+ } else {
177
+ *(int64_t *)args_ptr = v;
178
+ args_ptr += 8;
179
+ }
180
+ } break;
181
+ case PrimitiveKind::UInt8:
182
+ case PrimitiveKind::UInt16:
183
+ case PrimitiveKind::UInt32:
184
+ case PrimitiveKind::UInt64: {
185
+ if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
186
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
187
+ return false;
188
+ }
189
+
190
+ uint64_t v = CopyNumber<uint64_t>(value);
191
+
192
+ if (RG_LIKELY(param.gpr_count)) {
193
+ *(uint64_t *)(gpr_ptr++) = v;
194
+ } else {
195
+ *(uint64_t *)args_ptr = v;
196
+ args_ptr += 8;
197
+ }
198
+ } break;
199
+ case PrimitiveKind::String: {
200
+ const char *str;
201
+ if (RG_LIKELY(value.IsString())) {
202
+ str = PushString(value);
203
+ if (RG_UNLIKELY(!str))
204
+ return false;
205
+ } else if (IsNullOrUndefined(value)) {
206
+ str = nullptr;
207
+ } else {
208
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected string", GetValueType(instance, value), i + 1);
209
+ return false;
210
+ }
211
+
212
+ if (RG_LIKELY(param.gpr_count)) {
213
+ *(const char **)(gpr_ptr++) = str;
214
+ } else {
215
+ *(const char **)args_ptr = str;
216
+ args_ptr += 8;
217
+ }
218
+ } break;
219
+ case PrimitiveKind::String16: {
220
+ const char16_t *str16;
221
+ if (RG_LIKELY(value.IsString())) {
222
+ str16 = PushString16(value);
223
+ if (RG_UNLIKELY(!str16))
224
+ return false;
225
+ } else if (IsNullOrUndefined(value)) {
226
+ str16 = nullptr;
227
+ } else {
228
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected string", GetValueType(instance, value), i + 1);
229
+ return false;
230
+ }
231
+
232
+ if (RG_LIKELY(param.gpr_count)) {
233
+ *(const char16_t **)(gpr_ptr++) = str16;
234
+ } else {
235
+ *(const char16_t **)args_ptr = str16;
236
+ args_ptr += 8;
237
+ }
238
+ } break;
239
+ case PrimitiveKind::Pointer: {
240
+ uint8_t *ptr;
241
+
242
+ if (CheckValueTag(instance, value, param.type)) {
243
+ ptr = value.As<Napi::External<uint8_t>>().Data();
244
+ } else if (IsObject(value) && param.type->ref->primitive == PrimitiveKind::Record) {
245
+ Napi::Object obj = value.As<Napi::Object>();
246
+
247
+ if (RG_UNLIKELY(!AllocHeap(param.type->ref->size, 16, &ptr)))
248
+ return false;
249
+
250
+ if (param.directions & 1) {
251
+ if (!PushObject(obj, param.type->ref, ptr))
252
+ return false;
253
+ } else {
254
+ memset(ptr, 0, param.type->size);
255
+ }
256
+ if (param.directions & 2) {
257
+ OutObject *out = out_objects.AppendDefault();
258
+
259
+ out->ref.Reset(obj, 1);
260
+ out->ptr = ptr;
261
+ out->type = param.type->ref;
262
+ }
263
+ } else if (IsNullOrUndefined(value)) {
264
+ ptr = nullptr;
265
+ } else {
266
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected %3", GetValueType(instance, value), i + 1, param.type->name);
267
+ return false;
268
+ }
269
+
270
+ if (RG_LIKELY(param.gpr_count)) {
271
+ *(uint8_t **)(gpr_ptr++) = ptr;
272
+ } else {
273
+ *(uint8_t **)args_ptr = ptr;
274
+ args_ptr += 8;
275
+ }
276
+ } break;
277
+ case PrimitiveKind::Record: {
278
+ if (RG_UNLIKELY(!IsObject(value))) {
279
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected object", GetValueType(instance, value), i + 1);
280
+ return false;
281
+ }
282
+
283
+ Napi::Object obj = value.As<Napi::Object>();
284
+
285
+ if (!param.use_memory) {
286
+ RG_ASSERT(param.type->size <= 16);
287
+
288
+ // Split float or mixed int-float structs to registers
289
+ int realign = param.vec_count ? 8 : 0;
290
+
291
+ uint64_t buf[2] = { 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFFull };
292
+ if (!PushObject(obj, param.type, (uint8_t *)buf, realign))
293
+ return false;
294
+ uint64_t *ptr = buf;
295
+
296
+ if (param.gpr_first) {
297
+ *(gpr_ptr++) = *(ptr++);
298
+ *((param.vec_count ? vec_ptr : gpr_ptr)++) = *(ptr++);
299
+ gpr_ptr -= (param.gpr_count == 1);
300
+ } else if (param.vec_count) {
301
+ *(vec_ptr++) = *(ptr++);
302
+ *((param.gpr_count ? gpr_ptr : vec_ptr)++) = *(ptr++);
303
+ } else {
304
+ RG_ASSERT(param.type->align <= 8);
305
+
306
+ memcpy_safe(args_ptr, ptr, param.type->size);
307
+ args_ptr += AlignLen(param.type->size, 8);
308
+ }
309
+ } else {
310
+ uint8_t *ptr;
311
+ if (RG_UNLIKELY(!AllocHeap(param.type->size, 16, &ptr)))
312
+ return false;
313
+
314
+ if (param.gpr_count) {
315
+ RG_ASSERT(param.gpr_count == 1);
316
+ RG_ASSERT(param.vec_count == 0);
317
+
318
+ *(uint8_t **)(gpr_ptr++) = ptr;
319
+ } else {
320
+ *(uint8_t **)args_ptr = ptr;
321
+ args_ptr += 8;
322
+ }
323
+
324
+ if (!PushObject(obj, param.type, ptr))
325
+ return false;
326
+ }
327
+ } break;
328
+ case PrimitiveKind::Array: { RG_UNREACHABLE(); } break;
329
+ case PrimitiveKind::Float32: {
330
+ if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
331
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
332
+ return false;
333
+ }
334
+
335
+ float f = CopyNumber<float>(value);
336
+
337
+ if (RG_LIKELY(param.vec_count)) {
338
+ memset((uint8_t *)vec_ptr + 4, 0xFF, 4);
339
+ *(float *)(vec_ptr++) = f;
340
+ } else if (param.gpr_count) {
341
+ memset((uint8_t *)gpr_ptr + 4, 0xFF, 4);
342
+ *(float *)(gpr_ptr++) = f;
343
+ } else {
344
+ memset(args_ptr + 4, 0xFF, 4);
345
+ *(float *)args_ptr = f;
346
+ }
347
+ } break;
348
+ case PrimitiveKind::Float64: {
349
+ if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
350
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
351
+ return false;
352
+ }
353
+
354
+ double d = CopyNumber<double>(value);
355
+
356
+ if (RG_LIKELY(param.vec_count)) {
357
+ *(double *)(vec_ptr++) = d;
358
+ } else if (param.gpr_count) {
359
+ *(double *)(gpr_ptr++) = d;
360
+ } else {
361
+ *(double *)args_ptr = d;
362
+ args_ptr += 8;
363
+ }
364
+ } break;
365
+ }
366
+ }
367
+
368
+ sp = mem->stack.end();
369
+
370
+ return true;
371
+ }
372
+
373
+ void CallData::Execute()
374
+ {
375
+ #define PERFORM_CALL(Suffix) \
376
+ ([&]() { \
377
+ auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, sp) \
378
+ : ForwardCall ## Suffix(func->func, sp)); \
379
+ return ret; \
380
+ })()
381
+
382
+ // Execute and convert return value
383
+ switch (func->ret.type->primitive) {
384
+ case PrimitiveKind::Void:
385
+ case PrimitiveKind::Bool:
386
+ case PrimitiveKind::Int8:
387
+ case PrimitiveKind::UInt8:
388
+ case PrimitiveKind::Int16:
389
+ case PrimitiveKind::UInt16:
390
+ case PrimitiveKind::Int32:
391
+ case PrimitiveKind::UInt32:
392
+ case PrimitiveKind::Int64:
393
+ case PrimitiveKind::UInt64:
394
+ case PrimitiveKind::String:
395
+ case PrimitiveKind::String16:
396
+ case PrimitiveKind::Pointer: { result.u64 = PERFORM_CALL(GG).a0; } break;
397
+ case PrimitiveKind::Record: {
398
+ if (func->ret.gpr_first && !func->ret.vec_count) {
399
+ A0A1Ret ret = PERFORM_CALL(GG);
400
+ memcpy(&result.buf, &ret, RG_SIZE(ret));
401
+ } else if (func->ret.gpr_first) {
402
+ A0Fa0Ret ret = PERFORM_CALL(GD);
403
+ memcpy(&result.buf, &ret, RG_SIZE(ret));
404
+ } else if (func->ret.vec_count == 2) {
405
+ Fa0Fa1Ret ret = PERFORM_CALL(DD);
406
+ memcpy(&result.buf, &ret, RG_SIZE(ret));
407
+ } else {
408
+ Fa0A0Ret ret = PERFORM_CALL(DG);
409
+ memcpy(&result.buf, &ret, RG_SIZE(ret));
410
+ }
411
+ } break;
412
+ case PrimitiveKind::Array: { RG_UNREACHABLE(); } break;
413
+ case PrimitiveKind::Float32: { result.f = PERFORM_CALL(F); } break;
414
+ case PrimitiveKind::Float64: { result.d = PERFORM_CALL(DD).fa0; } break;
415
+ }
416
+
417
+ #undef PERFORM_CALL
418
+ }
419
+
420
+ Napi::Value CallData::Complete()
421
+ {
422
+ for (const OutObject &out: out_objects) {
423
+ Napi::Object obj = out.ref.Value().As<Napi::Object>();
424
+ PopObject(obj, out.ptr, out.type);
425
+ }
426
+
427
+ switch (func->ret.type->primitive) {
428
+ case PrimitiveKind::Void: return env.Null();
429
+ case PrimitiveKind::Bool: return Napi::Boolean::New(env, result.u32);
430
+ case PrimitiveKind::Int8:
431
+ case PrimitiveKind::UInt8:
432
+ case PrimitiveKind::Int16:
433
+ case PrimitiveKind::UInt16:
434
+ case PrimitiveKind::Int32:
435
+ case PrimitiveKind::UInt32: return Napi::Number::New(env, (double)result.u32);
436
+ case PrimitiveKind::Int64: return Napi::BigInt::New(env, (int64_t)result.u64);
437
+ case PrimitiveKind::UInt64: return Napi::BigInt::New(env, result.u64);
438
+ case PrimitiveKind::String: return Napi::String::New(env, (const char *)result.ptr);
439
+ case PrimitiveKind::String16: return Napi::String::New(env, (const char16_t *)result.ptr);
440
+ case PrimitiveKind::Pointer: {
441
+ Napi::External<void> external = Napi::External<void>::New(env, result.ptr);
442
+ SetValueTag(instance, external, func->ret.type);
443
+
444
+ return external;
445
+ } break;
446
+ case PrimitiveKind::Record: {
447
+ if (func->ret.vec_count) { // HFA
448
+ Napi::Object obj = PopObject((const uint8_t *)&result.buf, func->ret.type, 8);
449
+ return obj;
450
+ } else {
451
+ const uint8_t *ptr = return_ptr ? (const uint8_t *)return_ptr
452
+ : (const uint8_t *)&result.buf;
453
+
454
+ Napi::Object obj = PopObject(ptr, func->ret.type);
455
+ return obj;
456
+ }
457
+ } break;
458
+ case PrimitiveKind::Array: { RG_UNREACHABLE(); } break;
459
+ case PrimitiveKind::Float32: return Napi::Number::New(env, (double)result.f);
460
+ case PrimitiveKind::Float64: return Napi::Number::New(env, result.d);
461
+ }
462
+
463
+ RG_UNREACHABLE();
464
+ }
465
+
466
+ }
467
+
468
+ #endif
@@ -0,0 +1,129 @@
1
+ // This program is free software: you can redistribute it and/or modify
2
+ // it under the terms of the GNU Affero General Public License as published by
3
+ // the Free Software Foundation, either version 3 of the License, or
4
+ // (at your option) any later version.
5
+ //
6
+ // This program is distributed in the hope that it will be useful,
7
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
8
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9
+ // GNU Affero General Public License for more details.
10
+
11
+ // You should have received a copy of the GNU Affero General Public License
12
+ // along with this program. If not, see https://www.gnu.org/licenses/.
13
+
14
+ // These three are the same, but they differ (in the C side) by their return type.
15
+ // Unlike the three next functions, these ones don't forward FA argument registers.
16
+ .global ForwardCallGG
17
+ .global ForwardCallF
18
+ .global ForwardCallDG
19
+ .global ForwardCallGD
20
+ .global ForwardCallDD
21
+
22
+ // The X variants are slightly slower, and are used when FA arguments must be forwarded.
23
+ .global ForwardCallXGG
24
+ .global ForwardCallXF
25
+ .global ForwardCallXDG
26
+ .global ForwardCallXGD
27
+ .global ForwardCallXDD
28
+
29
+ // Copy function pointer to t0, in order to save it through argument forwarding.
30
+ // Save SP in s1, and use carefully assembled stack provided by caller.
31
+ .macro prologue
32
+ addi sp, sp, -16
33
+ mv t0, a0
34
+ sd ra, 0(sp)
35
+ sd s1, 8(sp)
36
+ mv s1, sp
37
+ addi sp, a1, 128
38
+ .endm
39
+
40
+ // Call native function.
41
+ // Once done, restore normal stack pointer and return.
42
+ // The return value is passed untouched through registers.
43
+ .macro epilogue
44
+ jalr t0
45
+ mv sp, s1
46
+ ld ra, 0(sp)
47
+ ld s1, 8(sp)
48
+ addi sp, sp, 16
49
+ ret
50
+ .endm
51
+
52
+ // Prepare general purpose argument registers from array passed by caller.
53
+ .macro forward_int
54
+ ld a7, 120(a1)
55
+ ld a6, 112(a1)
56
+ ld a5, 104(a1)
57
+ ld a4, 96(a1)
58
+ ld a3, 88(a1)
59
+ ld a2, 80(a1)
60
+ ld a0, 64(a1)
61
+ ld a1, 72(a1)
62
+ .endm
63
+
64
+ // Prepare vector argument registers from array passed by caller.
65
+ .macro forward_vec
66
+ fld fa7, 56(a1)
67
+ fld fa6, 48(a1)
68
+ fld fa5, 40(a1)
69
+ fld fa4, 32(a1)
70
+ fld fa3, 24(a1)
71
+ fld fa2, 16(a1)
72
+ fld fa1, 8(a1)
73
+ fld fa0, 0(a1)
74
+ .endm
75
+
76
+ ForwardCallGG:
77
+ prologue
78
+ forward_int
79
+ epilogue
80
+
81
+ ForwardCallF:
82
+ prologue
83
+ forward_int
84
+ epilogue
85
+
86
+ ForwardCallDG:
87
+ prologue
88
+ forward_int
89
+ epilogue
90
+
91
+ ForwardCallGD:
92
+ prologue
93
+ forward_int
94
+ epilogue
95
+
96
+ ForwardCallDD:
97
+ prologue
98
+ forward_int
99
+ epilogue
100
+
101
+ ForwardCallXGG:
102
+ prologue
103
+ forward_vec
104
+ forward_int
105
+ epilogue
106
+
107
+ ForwardCallXF:
108
+ prologue
109
+ forward_vec
110
+ forward_int
111
+ epilogue
112
+
113
+ ForwardCallXDG:
114
+ prologue
115
+ forward_vec
116
+ forward_int
117
+ epilogue
118
+
119
+ ForwardCallXGD:
120
+ prologue
121
+ forward_vec
122
+ forward_int
123
+ epilogue
124
+
125
+ ForwardCallXDD:
126
+ prologue
127
+ forward_vec
128
+ forward_int
129
+ epilogue
@@ -11,7 +11,7 @@
11
11
  // You should have received a copy of the GNU Affero General Public License
12
12
  // along with this program. If not, see https://www.gnu.org/licenses/.
13
13
 
14
- #if defined(__x86_64__) && !defined(_WIN64)
14
+ #if defined(__x86_64__) && !defined(_WIN32)
15
15
 
16
16
  #include "vendor/libcc/libcc.hh"
17
17
  #include "ffi.hh"
@@ -165,7 +165,7 @@ static void AnalyseParameter(ParameterInfo *param, int gpr_avail, int xmm_avail)
165
165
  xmm_count += (cls == RegisterClass::SSE);
166
166
  }
167
167
 
168
- if (gpr_count <= gpr_avail && xmm_count <= xmm_avail){
168
+ if (gpr_count <= gpr_avail && xmm_count <= xmm_avail) {
169
169
  param->gpr_count = (int8_t)gpr_count;
170
170
  param->xmm_count = (int8_t)xmm_count;
171
171
  param->gpr_first = (classes[0] == RegisterClass::Integer);
@@ -420,8 +420,7 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
420
420
  }
421
421
  }
422
422
 
423
- stack = MakeSpan(mem->stack.end(), old_stack_mem.end() - mem->stack.end());
424
- heap = MakeSpan(old_heap_mem.ptr, mem->heap.ptr - old_heap_mem.ptr);
423
+ sp = mem->stack.end();
425
424
 
426
425
  return true;
427
426
  }
@@ -430,8 +429,8 @@ void CallData::Execute()
430
429
  {
431
430
  #define PERFORM_CALL(Suffix) \
432
431
  ([&]() { \
433
- auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, stack.ptr) \
434
- : ForwardCall ## Suffix(func->func, stack.ptr)); \
432
+ auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, sp) \
433
+ : ForwardCall ## Suffix(func->func, sp)); \
435
434
  return ret; \
436
435
  })()
437
436
 
@@ -453,16 +452,16 @@ void CallData::Execute()
453
452
  case PrimitiveKind::Record: {
454
453
  if (func->ret.gpr_first && !func->ret.xmm_count) {
455
454
  RaxRdxRet ret = PERFORM_CALL(GG);
456
- memcpy_safe(&result.buf, &ret, RG_SIZE(ret));
455
+ memcpy(&result.buf, &ret, RG_SIZE(ret));
457
456
  } else if (func->ret.gpr_first) {
458
457
  RaxXmm0Ret ret = PERFORM_CALL(GD);
459
- memcpy_safe(&result.buf, &ret, RG_SIZE(ret));
458
+ memcpy(&result.buf, &ret, RG_SIZE(ret));
460
459
  } else if (func->ret.xmm_count == 2) {
461
460
  Xmm0Xmm1Ret ret = PERFORM_CALL(DD);
462
- memcpy_safe(&result.buf, &ret, RG_SIZE(ret));
461
+ memcpy(&result.buf, &ret, RG_SIZE(ret));
463
462
  } else {
464
463
  Xmm0RaxRet ret = PERFORM_CALL(DG);
465
- memcpy_safe(&result.buf, &ret, RG_SIZE(ret));
464
+ memcpy(&result.buf, &ret, RG_SIZE(ret));
466
465
  }
467
466
  } break;
468
467
  case PrimitiveKind::Array: { RG_UNREACHABLE(); } break;
@@ -11,7 +11,7 @@
11
11
  // You should have received a copy of the GNU Affero General Public License
12
12
  // along with this program. If not, see https://www.gnu.org/licenses/.
13
13
 
14
- #ifdef _WIN64
14
+ #if defined(_WIN32) && (defined(__x86_64__) || defined(_M_AMD64))
15
15
 
16
16
  #include "vendor/libcc/libcc.hh"
17
17
  #include "ffi.hh"
@@ -41,9 +41,7 @@ bool AnalyseFunction(InstanceData *, FunctionInfo *func)
41
41
 
42
42
  for (ParameterInfo &param: func->parameters) {
43
43
  param.regular = IsRegular(param.type->size);
44
-
45
- func->forward_fp |= (param.type->primitive == PrimitiveKind::Float32 ||
46
- param.type->primitive == PrimitiveKind::Float64);
44
+ func->forward_fp |= IsFloat(param.type);
47
45
  }
48
46
 
49
47
  func->args_size = AlignLen(8 * std::max((Size)4, func->parameters.len + !func->ret.regular), 16);
@@ -204,8 +202,7 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
204
202
  }
205
203
  }
206
204
 
207
- stack = MakeSpan(mem->stack.end(), old_stack_mem.end() - mem->stack.end());
208
- heap = MakeSpan(old_heap_mem.ptr, mem->heap.ptr - old_heap_mem.ptr);
205
+ sp = mem->stack.end();
209
206
 
210
207
  return true;
211
208
  }
@@ -214,8 +211,8 @@ void CallData::Execute()
214
211
  {
215
212
  #define PERFORM_CALL(Suffix) \
216
213
  ([&]() { \
217
- auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, stack.ptr) \
218
- : ForwardCall ## Suffix(func->func, stack.ptr)); \
214
+ auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, sp) \
215
+ : ForwardCall ## Suffix(func->func, sp)); \
219
216
  return ret; \
220
217
  })()
221
218