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.
- package/CMakeLists.txt +13 -7
- package/README.md +15 -26
- package/build/qemu/1.1.4/koffi_darwin_x64.tar.gz +0 -0
- package/build/qemu/1.1.4/koffi_freebsd_arm64.tar.gz +0 -0
- package/build/qemu/1.1.4/koffi_freebsd_ia32.tar.gz +0 -0
- package/build/qemu/1.1.4/koffi_freebsd_x64.tar.gz +0 -0
- package/build/qemu/1.1.4/koffi_linux_arm.tar.gz +0 -0
- package/build/qemu/1.1.4/koffi_linux_arm64.tar.gz +0 -0
- package/build/qemu/1.1.4/koffi_linux_ia32.tar.gz +0 -0
- package/build/qemu/1.1.4/koffi_linux_riscv64.tar.gz +0 -0
- package/build/qemu/1.1.4/koffi_linux_x64.tar.gz +0 -0
- package/build/qemu/1.1.4/koffi_openbsd_ia32.tar.gz +0 -0
- package/build/qemu/1.1.4/koffi_openbsd_x64.tar.gz +0 -0
- package/build/qemu/1.1.4/koffi_win32_ia32.tar.gz +0 -0
- package/build/qemu/1.1.4/koffi_win32_x64.tar.gz +0 -0
- package/package.json +2 -2
- package/qemu/qemu.js +13 -10
- package/qemu/registry/machines.json +138 -3
- package/qemu/registry/sha256sum.txt +27 -12
- package/src/abi_arm32.cc +29 -16
- package/src/abi_arm64.cc +33 -17
- package/src/abi_riscv64.cc +468 -0
- package/src/abi_riscv64_fwd.S +129 -0
- package/src/abi_x64_sysv.cc +9 -10
- package/src/abi_x64_win.cc +5 -8
- package/src/abi_x86.cc +11 -6
- package/src/call.cc +24 -36
- package/src/call.hh +14 -24
- package/src/ffi.cc +75 -27
- package/src/ffi.hh +13 -5
- package/src/parser.cc +48 -26
- package/src/parser.hh +3 -1
- package/src/util.cc +26 -57
- package/src/util.hh +17 -1
- package/test/CMakeLists.txt +3 -0
- package/test/misc.c +34 -0
- package/vendor/_patches/glfw_001_fix_openbsd_xlib_soname.patch +145 -0
- package/vendor/libcc/libcc.cc +7 -7
- package/vendor/libcc/libcc.hh +8 -2
- package/vendor/raylib/src/external/glfw/src/egl_context.c +6 -0
- package/vendor/raylib/src/external/glfw/src/osmesa_context.c +2 -0
- package/vendor/raylib/src/external/glfw/src/vulkan.c +2 -0
- package/vendor/raylib/src/external/glfw/src/x11_init.c +20 -0
- package/build/qemu/1.1.1/koffi_darwin_x64.tar.gz +0 -0
- package/build/qemu/1.1.1/koffi_freebsd_arm64.tar.gz +0 -0
- package/build/qemu/1.1.1/koffi_freebsd_ia32.tar.gz +0 -0
- package/build/qemu/1.1.1/koffi_freebsd_x64.tar.gz +0 -0
- package/build/qemu/1.1.1/koffi_linux_arm.tar.gz +0 -0
- package/build/qemu/1.1.1/koffi_linux_arm64.tar.gz +0 -0
- package/build/qemu/1.1.1/koffi_linux_ia32.tar.gz +0 -0
- package/build/qemu/1.1.1/koffi_linux_x64.tar.gz +0 -0
- package/build/qemu/1.1.1/koffi_win32_ia32.tar.gz +0 -0
- 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 ¶m: func->parameters) {
|
|
107
|
+
AnalyseParameter(¶m, 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 ¶m = 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
|
package/src/abi_x64_sysv.cc
CHANGED
|
@@ -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(
|
|
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
|
-
|
|
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,
|
|
434
|
-
: ForwardCall ## Suffix(func->func,
|
|
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
|
-
|
|
455
|
+
memcpy(&result.buf, &ret, RG_SIZE(ret));
|
|
457
456
|
} else if (func->ret.gpr_first) {
|
|
458
457
|
RaxXmm0Ret ret = PERFORM_CALL(GD);
|
|
459
|
-
|
|
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
|
-
|
|
461
|
+
memcpy(&result.buf, &ret, RG_SIZE(ret));
|
|
463
462
|
} else {
|
|
464
463
|
Xmm0RaxRet ret = PERFORM_CALL(DG);
|
|
465
|
-
|
|
464
|
+
memcpy(&result.buf, &ret, RG_SIZE(ret));
|
|
466
465
|
}
|
|
467
466
|
} break;
|
|
468
467
|
case PrimitiveKind::Array: { RG_UNREACHABLE(); } break;
|
package/src/abi_x64_win.cc
CHANGED
|
@@ -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
|
-
#
|
|
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 ¶m: 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
|
-
|
|
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,
|
|
218
|
-
: ForwardCall ## Suffix(func->func,
|
|
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
|
|