koffi 2.2.2-beta.5 → 2.2.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.
- package/ChangeLog.md +14 -0
- package/doc/callbacks.md +10 -3
- package/doc/contribute.md +1 -1
- package/package.json +2 -2
- package/src/koffi/build/2.2.2/koffi_darwin_arm64.tar.gz +0 -0
- package/src/koffi/build/2.2.2/koffi_darwin_x64.tar.gz +0 -0
- package/src/koffi/build/2.2.2/koffi_freebsd_arm64.tar.gz +0 -0
- package/src/koffi/build/2.2.2/koffi_freebsd_ia32.tar.gz +0 -0
- package/src/koffi/build/2.2.2/koffi_freebsd_x64.tar.gz +0 -0
- package/src/koffi/build/2.2.2/koffi_linux_arm32hf.tar.gz +0 -0
- package/src/koffi/build/2.2.2/koffi_linux_arm64.tar.gz +0 -0
- package/src/koffi/build/2.2.2/koffi_linux_ia32.tar.gz +0 -0
- package/src/koffi/build/2.2.2/koffi_linux_riscv64hf64.tar.gz +0 -0
- package/src/koffi/build/2.2.2/koffi_linux_x64.tar.gz +0 -0
- package/src/koffi/build/2.2.2/koffi_openbsd_ia32.tar.gz +0 -0
- package/src/koffi/build/2.2.2/koffi_openbsd_x64.tar.gz +0 -0
- package/src/koffi/build/2.2.2/koffi_win32_arm64.tar.gz +0 -0
- package/src/koffi/build/2.2.2/koffi_win32_ia32.tar.gz +0 -0
- package/src/koffi/build/2.2.2/koffi_win32_x64.tar.gz +0 -0
- package/src/koffi/src/abi_arm32.cc +3 -70
- package/src/koffi/src/abi_arm32_fwd.S +6054 -97
- package/src/koffi/src/abi_arm64.cc +3 -70
- package/src/koffi/src/abi_arm64_fwd.S +6050 -93
- package/src/koffi/src/abi_arm64_fwd.asm +8082 -141
- package/src/koffi/src/abi_riscv64.cc +3 -70
- package/src/koffi/src/abi_riscv64_fwd.S +6044 -87
- package/src/koffi/src/abi_trampolines.inc +2065 -0
- package/src/koffi/src/abi_x64_sysv.cc +3 -70
- package/src/koffi/src/abi_x64_sysv_fwd.S +6048 -91
- package/src/koffi/src/abi_x64_win.cc +4 -71
- package/src/koffi/src/abi_x64_win_fwd.asm +8018 -77
- package/src/koffi/src/abi_x86.cc +4 -71
- package/src/koffi/src/abi_x86_fwd.S +6056 -99
- package/src/koffi/src/abi_x86_fwd.asm +8027 -86
- package/src/koffi/src/call.cc +23 -16
- package/src/koffi/src/call.hh +2 -4
- package/src/koffi/src/ffi.cc +35 -33
- package/src/koffi/src/ffi.hh +16 -5
- package/src/koffi/test/callbacks.js +11 -10
- package/src/koffi/test/misc.c +30 -17
- package/src/koffi/{qemu → tools}/qemu/.gitkeep +0 -0
- package/src/koffi/{qemu → tools}/qemu.js +4 -1
- package/src/koffi/{qemu → tools}/registry/machines.json +0 -0
- package/src/koffi/{qemu → tools}/registry/sha256sum.txt +0 -0
- package/src/koffi/tools/write_trampolines.py +138 -0
- package/src/koffi/build/2.2.2-beta.5/koffi_darwin_arm64.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.5/koffi_darwin_x64.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.5/koffi_freebsd_arm64.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.5/koffi_freebsd_ia32.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.5/koffi_freebsd_x64.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.5/koffi_linux_arm32hf.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.5/koffi_linux_arm64.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.5/koffi_linux_ia32.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.5/koffi_linux_riscv64hf64.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.5/koffi_linux_x64.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.5/koffi_openbsd_ia32.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.5/koffi_openbsd_x64.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.5/koffi_win32_arm64.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.5/koffi_win32_ia32.tar.gz +0 -0
- package/src/koffi/build/2.2.2-beta.5/koffi_win32_x64.tar.gz +0 -0
package/src/koffi/src/call.cc
CHANGED
|
@@ -53,19 +53,20 @@ CallData::~CallData()
|
|
|
53
53
|
mem->stack = old_stack_mem;
|
|
54
54
|
mem->heap = old_heap_mem;
|
|
55
55
|
|
|
56
|
-
if (used_trampolines) {
|
|
56
|
+
if (used_trampolines.len) {
|
|
57
57
|
std::lock_guard<std::mutex> lock(shared.mutex);
|
|
58
58
|
|
|
59
|
-
for (Size i =
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
for (Size i = used_trampolines.len - 1; i >= 0; i--) {
|
|
60
|
+
int16_t idx = used_trampolines[i];
|
|
61
|
+
TrampolineInfo *trampoline = &shared.trampolines[idx];
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
63
|
+
RG_ASSERT(!trampoline->func.IsEmpty());
|
|
64
|
+
|
|
65
|
+
trampoline->func.Reset();
|
|
66
|
+
trampoline->recv.Reset();
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
shared.available.Append(idx);
|
|
69
|
+
}
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
instance->temporaries -= mem->temporary;
|
|
@@ -80,6 +81,9 @@ CallData::~CallData()
|
|
|
80
81
|
void CallData::RelaySafe(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
|
|
81
82
|
{
|
|
82
83
|
if (std::this_thread::get_id() != instance->main_thread_id) {
|
|
84
|
+
// JS/V8 is single-threaded, and runs on main_thread_id. Forward the call
|
|
85
|
+
// to the JS event loop.
|
|
86
|
+
|
|
83
87
|
RelayContext ctx;
|
|
84
88
|
|
|
85
89
|
ctx.call = this;
|
|
@@ -1025,19 +1029,21 @@ void CallData::PopOutArguments()
|
|
|
1025
1029
|
|
|
1026
1030
|
void *CallData::ReserveTrampoline(const FunctionInfo *proto, Napi::Function func)
|
|
1027
1031
|
{
|
|
1028
|
-
|
|
1032
|
+
int16_t idx;
|
|
1029
1033
|
{
|
|
1030
1034
|
std::lock_guard<std::mutex> lock(shared.mutex);
|
|
1031
1035
|
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
+
if (RG_UNLIKELY(!shared.available.len)) {
|
|
1037
|
+
ThrowError<Napi::Error>(env, "Too many callbacks are in use (max = %1)", MaxTrampolines);
|
|
1038
|
+
return env.Null();
|
|
1039
|
+
}
|
|
1040
|
+
if (RG_UNLIKELY(!used_trampolines.Available())) {
|
|
1041
|
+
ThrowError<Napi::Error>(env, "This call uses too many temporary callbacks (max = %1)", RG_LEN(used_trampolines.data));
|
|
1036
1042
|
return env.Null();
|
|
1037
1043
|
}
|
|
1038
1044
|
|
|
1039
|
-
shared.
|
|
1040
|
-
used_trampolines
|
|
1045
|
+
idx = shared.available.data[--shared.available.len];
|
|
1046
|
+
used_trampolines.Append(idx);
|
|
1041
1047
|
}
|
|
1042
1048
|
|
|
1043
1049
|
TrampolineInfo *trampoline = &shared.trampolines[idx];
|
|
@@ -1048,6 +1054,7 @@ void *CallData::ReserveTrampoline(const FunctionInfo *proto, Napi::Function func
|
|
|
1048
1054
|
trampoline->generation = (int32_t)mem->generation;
|
|
1049
1055
|
|
|
1050
1056
|
void *ptr = GetTrampoline(idx, proto);
|
|
1057
|
+
|
|
1051
1058
|
return ptr;
|
|
1052
1059
|
}
|
|
1053
1060
|
|
package/src/koffi/src/call.hh
CHANGED
|
@@ -41,8 +41,7 @@ class alignas(8) CallData {
|
|
|
41
41
|
Span<uint8_t> old_stack_mem;
|
|
42
42
|
Span<uint8_t> old_heap_mem;
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
LocalArray<int16_t, 16> used_trampolines;
|
|
46
45
|
LocalArray<OutArgument, MaxOutParameters> out_arguments;
|
|
47
46
|
|
|
48
47
|
uint8_t *new_sp;
|
|
@@ -112,7 +111,6 @@ private:
|
|
|
112
111
|
|
|
113
112
|
void *ReserveTrampoline(const FunctionInfo *proto, Napi::Function func);
|
|
114
113
|
};
|
|
115
|
-
RG_STATIC_ASSERT(MaxTrampolines <= 32);
|
|
116
114
|
|
|
117
115
|
template <typename T>
|
|
118
116
|
inline bool CallData::AllocStack(Size size, Size align, T **out_ptr)
|
|
@@ -165,6 +163,6 @@ inline T *CallData::AllocHeap(Size size, Size align)
|
|
|
165
163
|
}
|
|
166
164
|
}
|
|
167
165
|
|
|
168
|
-
void *GetTrampoline(
|
|
166
|
+
void *GetTrampoline(int16_t idx, const FunctionInfo *proto);
|
|
169
167
|
|
|
170
168
|
}
|
package/src/koffi/src/ffi.cc
CHANGED
|
@@ -1001,6 +1001,8 @@ static Napi::Value GetTypeDefinition(const Napi::CallbackInfo &info)
|
|
|
1001
1001
|
|
|
1002
1002
|
static InstanceMemory *AllocateMemory(InstanceData *instance, Size stack_size, Size heap_size)
|
|
1003
1003
|
{
|
|
1004
|
+
std::lock_guard<std::mutex> lock(instance->memories_mutex);
|
|
1005
|
+
|
|
1004
1006
|
for (Size i = 1; i < instance->memories.len; i++) {
|
|
1005
1007
|
InstanceMemory *mem = instance->memories[i];
|
|
1006
1008
|
|
|
@@ -1063,9 +1065,6 @@ static Napi::Value TranslateNormalCall(const Napi::CallbackInfo &info)
|
|
|
1063
1065
|
InstanceMemory *mem = instance->memories[0];
|
|
1064
1066
|
CallData call(env, instance, mem);
|
|
1065
1067
|
|
|
1066
|
-
RG_DEFER_C(prev_call = exec_call) { exec_call = prev_call; };
|
|
1067
|
-
exec_call = &call;
|
|
1068
|
-
|
|
1069
1068
|
if (!RG_UNLIKELY(call.Prepare(func, info)))
|
|
1070
1069
|
return env.Null();
|
|
1071
1070
|
|
|
@@ -1111,7 +1110,7 @@ static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
|
|
|
1111
1110
|
for (Size i = func.parameters.len; i < (Size)info.Length(); i += 2) {
|
|
1112
1111
|
ParameterInfo param = {};
|
|
1113
1112
|
|
|
1114
|
-
param.type = ResolveType(info[i], ¶m.directions);
|
|
1113
|
+
param.type = ResolveType(info[(uint32_t)i], ¶m.directions);
|
|
1115
1114
|
|
|
1116
1115
|
if (RG_UNLIKELY(!param.type))
|
|
1117
1116
|
return env.Null();
|
|
@@ -1436,19 +1435,16 @@ static Napi::Value RegisterCallback(const Napi::CallbackInfo &info)
|
|
|
1436
1435
|
return env.Null();
|
|
1437
1436
|
}
|
|
1438
1437
|
|
|
1439
|
-
|
|
1438
|
+
int16_t idx;
|
|
1440
1439
|
{
|
|
1441
1440
|
std::lock_guard<std::mutex> lock(shared.mutex);
|
|
1442
1441
|
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
if (RG_UNLIKELY(idx >= MaxTrampolines)) {
|
|
1446
|
-
ThrowError<Napi::Error>(env, "Too many registered callbacks are in use (max = %1)", MaxTrampolines);
|
|
1442
|
+
if (RG_UNLIKELY(!shared.available.len)) {
|
|
1443
|
+
ThrowError<Napi::Error>(env, "Too many callbacks are in use (max = %1)", MaxTrampolines);
|
|
1447
1444
|
return env.Null();
|
|
1448
1445
|
}
|
|
1449
1446
|
|
|
1450
|
-
shared.
|
|
1451
|
-
idx += MaxTrampolines;
|
|
1447
|
+
idx = shared.available.data[--shared.available.len];
|
|
1452
1448
|
}
|
|
1453
1449
|
|
|
1454
1450
|
TrampolineInfo *trampoline = &shared.trampolines[idx];
|
|
@@ -1467,6 +1463,9 @@ static Napi::Value RegisterCallback(const Napi::CallbackInfo &info)
|
|
|
1467
1463
|
Napi::External<void> external = Napi::External<void>::New(env, ptr);
|
|
1468
1464
|
SetValueTag(instance, external, type->ref.marker);
|
|
1469
1465
|
|
|
1466
|
+
// Cache index for fast unregistration
|
|
1467
|
+
instance->trampolines_map.Set(ptr, idx);
|
|
1468
|
+
|
|
1470
1469
|
return external;
|
|
1471
1470
|
}
|
|
1472
1471
|
|
|
@@ -1487,31 +1486,33 @@ static Napi::Value UnregisterCallback(const Napi::CallbackInfo &info)
|
|
|
1487
1486
|
Napi::External<void> external = info[0].As<Napi::External<void>>();
|
|
1488
1487
|
void *ptr = external.Data();
|
|
1489
1488
|
|
|
1490
|
-
|
|
1489
|
+
int16_t idx;
|
|
1491
1490
|
{
|
|
1492
|
-
|
|
1491
|
+
int16_t *it = instance->trampolines_map.Find(ptr);
|
|
1493
1492
|
|
|
1494
|
-
|
|
1495
|
-
|
|
1493
|
+
if (RG_UNLIKELY(!it)) {
|
|
1494
|
+
ThrowError<Napi::Error>(env, "Could not find matching registered callback");
|
|
1495
|
+
return env.Null();
|
|
1496
|
+
}
|
|
1496
1497
|
|
|
1497
|
-
|
|
1498
|
-
|
|
1498
|
+
idx = *it;
|
|
1499
|
+
instance->trampolines_map.Remove(it);
|
|
1500
|
+
}
|
|
1499
1501
|
|
|
1500
|
-
|
|
1502
|
+
// Release shared trampoline safely
|
|
1503
|
+
{
|
|
1504
|
+
std::lock_guard<std::mutex> lock(shared.mutex);
|
|
1501
1505
|
|
|
1502
|
-
|
|
1503
|
-
|
|
1506
|
+
TrampolineInfo *trampoline = &shared.trampolines[idx];
|
|
1507
|
+
RG_ASSERT(!trampoline->func.IsEmpty());
|
|
1504
1508
|
|
|
1505
|
-
|
|
1506
|
-
|
|
1509
|
+
trampoline->func.Reset();
|
|
1510
|
+
trampoline->recv.Reset();
|
|
1507
1511
|
|
|
1508
|
-
|
|
1509
|
-
}
|
|
1510
|
-
}
|
|
1512
|
+
shared.available.Append(idx);
|
|
1511
1513
|
}
|
|
1512
1514
|
|
|
1513
|
-
|
|
1514
|
-
return env.Null();
|
|
1515
|
+
return env.Undefined();
|
|
1515
1516
|
}
|
|
1516
1517
|
|
|
1517
1518
|
LibraryHolder::~LibraryHolder()
|
|
@@ -1709,18 +1710,16 @@ InstanceData::~InstanceData()
|
|
|
1709
1710
|
delete mem;
|
|
1710
1711
|
}
|
|
1711
1712
|
|
|
1712
|
-
// Clean-up leftover
|
|
1713
|
+
// Clean-up leftover trampoline references
|
|
1713
1714
|
{
|
|
1714
1715
|
std::lock_guard<std::mutex> lock(shared.mutex);
|
|
1715
1716
|
|
|
1716
|
-
for (
|
|
1717
|
-
|
|
1717
|
+
for (int16_t idx = 0; idx < MaxTrampolines; idx++) {
|
|
1718
|
+
TrampolineInfo *trampoline = &shared.trampolines[idx];
|
|
1718
1719
|
|
|
1719
|
-
if (
|
|
1720
|
+
if (trampoline->func.IsEmpty())
|
|
1720
1721
|
continue;
|
|
1721
1722
|
|
|
1722
|
-
TrampolineInfo *trampoline = &shared.trampolines[idx];
|
|
1723
|
-
|
|
1724
1723
|
if (trampoline->func.Env().GetInstanceData<InstanceData>() == this) {
|
|
1725
1724
|
trampoline->func.Reset();
|
|
1726
1725
|
trampoline->recv.Reset();
|
|
@@ -1891,6 +1890,9 @@ extern "C" void RelayCallback(Size idx, uint8_t *own_sp, uint8_t *caller_sp, Bac
|
|
|
1891
1890
|
if (RG_LIKELY(exec_call)) {
|
|
1892
1891
|
exec_call->RelaySafe(idx, own_sp, caller_sp, out_reg);
|
|
1893
1892
|
} else {
|
|
1893
|
+
// This happens if the callback pointer is called from a different thread
|
|
1894
|
+
// than the one that runs the FFI call (sync or async).
|
|
1895
|
+
|
|
1894
1896
|
TrampolineInfo *trampoline = &shared.trampolines[idx];
|
|
1895
1897
|
|
|
1896
1898
|
Napi::Env env = trampoline->func.Env();
|
package/src/koffi/src/ffi.hh
CHANGED
|
@@ -30,7 +30,7 @@ static const Size DefaultMaxTypeSize = Mebibytes(64);
|
|
|
30
30
|
static const int MaxAsyncCalls = 256;
|
|
31
31
|
static const Size MaxParameters = 32;
|
|
32
32
|
static const Size MaxOutParameters = 16;
|
|
33
|
-
static const Size MaxTrampolines =
|
|
33
|
+
static const Size MaxTrampolines = 1024;
|
|
34
34
|
|
|
35
35
|
extern const int TypeInfoMarker;
|
|
36
36
|
extern const int CastMarker;
|
|
@@ -247,12 +247,15 @@ struct InstanceData {
|
|
|
247
247
|
const TypeInfo *char_type;
|
|
248
248
|
const TypeInfo *char16_type;
|
|
249
249
|
|
|
250
|
+
std::mutex memories_mutex;
|
|
250
251
|
LocalArray<InstanceMemory *, 9> memories;
|
|
251
252
|
int temporaries = 0;
|
|
252
253
|
|
|
253
254
|
std::thread::id main_thread_id;
|
|
254
255
|
napi_threadsafe_function broker = nullptr;
|
|
255
256
|
|
|
257
|
+
HashMap<void *, int16_t> trampolines_map;
|
|
258
|
+
|
|
256
259
|
BlockAllocator str_alloc;
|
|
257
260
|
|
|
258
261
|
Size sync_stack_size = DefaultSyncStackSize;
|
|
@@ -266,7 +269,6 @@ struct InstanceData {
|
|
|
266
269
|
RG_STATIC_ASSERT(DefaultResidentAsyncPools <= RG_LEN(InstanceData::memories.data) - 1);
|
|
267
270
|
RG_STATIC_ASSERT(DefaultMaxAsyncCalls >= DefaultResidentAsyncPools);
|
|
268
271
|
RG_STATIC_ASSERT(MaxAsyncCalls >= DefaultMaxAsyncCalls);
|
|
269
|
-
RG_STATIC_ASSERT(MaxTrampolines <= 16);
|
|
270
272
|
|
|
271
273
|
struct TrampolineInfo {
|
|
272
274
|
const FunctionInfo *proto;
|
|
@@ -279,10 +281,19 @@ struct TrampolineInfo {
|
|
|
279
281
|
struct SharedData {
|
|
280
282
|
std::mutex mutex;
|
|
281
283
|
|
|
282
|
-
TrampolineInfo trampolines[MaxTrampolines
|
|
283
|
-
|
|
284
|
-
|
|
284
|
+
TrampolineInfo trampolines[MaxTrampolines];
|
|
285
|
+
LocalArray<int16_t, MaxTrampolines> available;
|
|
286
|
+
|
|
287
|
+
SharedData()
|
|
288
|
+
{
|
|
289
|
+
available.len = MaxTrampolines;
|
|
290
|
+
|
|
291
|
+
for (int16_t i = 0; i < MaxTrampolines; i++) {
|
|
292
|
+
available[i] = i;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
285
295
|
};
|
|
296
|
+
RG_STATIC_ASSERT(MaxTrampolines <= INT16_MAX);
|
|
286
297
|
|
|
287
298
|
extern SharedData shared;
|
|
288
299
|
|
|
@@ -75,8 +75,7 @@ async function test() {
|
|
|
75
75
|
const ApplyStruct = lib.func('int ApplyStruct(int x, StructCallbacks callbacks)');
|
|
76
76
|
const SetIndirect = lib.func('void SetIndirect(IntCallback *func)');
|
|
77
77
|
const CallIndirect = lib.func('int CallIndirect(int x)');
|
|
78
|
-
const
|
|
79
|
-
const CallDirectThreaded = lib.func('int CallDirectThreaded(IntCallback *func, int x)');
|
|
78
|
+
const CallThreaded = lib.func('int CallThreaded(IntCallback *func, int x)');
|
|
80
79
|
const MakeVectors = lib.func('int MakeVectors(int len, VectorCallback *func)');
|
|
81
80
|
const CallQSort = lib.func('void CallQSort(_Inout_ void *base, size_t nmemb, size_t size, SortCallback *cb)');
|
|
82
81
|
const CallMeChar = lib.func('int CallMeChar(CharCallback *func)');
|
|
@@ -263,16 +262,18 @@ async function test() {
|
|
|
263
262
|
assert.equal(ret, 97 + 2 * 98);
|
|
264
263
|
}
|
|
265
264
|
|
|
266
|
-
// Use
|
|
267
|
-
for (let i = 0; i <
|
|
268
|
-
assert.equal(await util.promisify(CallDirectThreaded.async)(x => -x - 2, 27), -29);
|
|
269
|
-
|
|
270
|
-
// Use registered callback from secondary thread
|
|
271
|
-
for (let i = 0; i < 128; i++) {
|
|
265
|
+
// Use callbacks from secondary threads
|
|
266
|
+
for (let i = 0; i < 1024; i++) {
|
|
272
267
|
let cb = koffi.register(x => -x - 2, koffi.pointer(IntCallback));
|
|
273
|
-
|
|
274
268
|
SetIndirect(cb);
|
|
275
|
-
|
|
269
|
+
|
|
270
|
+
let results = await Promise.all([
|
|
271
|
+
util.promisify(CallThreaded.async)(x => -x - 4, 27),
|
|
272
|
+
util.promisify(CallThreaded.async)(null, 27)
|
|
273
|
+
]);
|
|
274
|
+
|
|
275
|
+
assert.equal(results[0], -31);
|
|
276
|
+
assert.equal(results[1], -29);
|
|
276
277
|
|
|
277
278
|
koffi.unregister(cb);
|
|
278
279
|
}
|
package/src/koffi/test/misc.c
CHANGED
|
@@ -681,17 +681,27 @@ EXPORT int CallIndirect(int x)
|
|
|
681
681
|
|
|
682
682
|
#ifdef _WIN32
|
|
683
683
|
|
|
684
|
-
|
|
684
|
+
typedef struct CallContext {
|
|
685
|
+
IntCallback *callback;
|
|
686
|
+
int *ptr;
|
|
687
|
+
} CallContext;
|
|
688
|
+
|
|
689
|
+
static DWORD WINAPI CallThreadedFunc(void *udata)
|
|
685
690
|
{
|
|
686
|
-
|
|
687
|
-
*ptr = callback(*ptr);
|
|
691
|
+
CallContext *ctx = (CallContext *)udata;
|
|
692
|
+
*ctx->ptr = ctx->callback(*ctx->ptr);
|
|
688
693
|
|
|
689
694
|
return 0;
|
|
690
695
|
}
|
|
691
696
|
|
|
692
|
-
EXPORT int
|
|
697
|
+
EXPORT int CallThreaded(IntCallback *func, int x)
|
|
693
698
|
{
|
|
694
|
-
|
|
699
|
+
CallContext ctx;
|
|
700
|
+
|
|
701
|
+
ctx.callback = func ? func : callback;
|
|
702
|
+
ctx.ptr = &x;
|
|
703
|
+
|
|
704
|
+
HANDLE h = CreateThread(NULL, 0, CallThreadedFunc, &ctx, 0, NULL);
|
|
695
705
|
if (!h) {
|
|
696
706
|
perror("CreateThread");
|
|
697
707
|
exit(1);
|
|
@@ -705,19 +715,28 @@ EXPORT int CallIndirectThreaded(int x)
|
|
|
705
715
|
|
|
706
716
|
#else
|
|
707
717
|
|
|
708
|
-
|
|
718
|
+
typedef struct CallContext {
|
|
719
|
+
IntCallback *callback;
|
|
720
|
+
int *ptr;
|
|
721
|
+
} CallContext;
|
|
722
|
+
|
|
723
|
+
static void *CallThreadedFunc(void *udata)
|
|
709
724
|
{
|
|
710
|
-
|
|
711
|
-
*ptr = callback(*ptr);
|
|
725
|
+
CallContext *ctx = (CallContext *)udata;
|
|
726
|
+
*ctx->ptr = ctx->callback(*ctx->ptr);
|
|
712
727
|
|
|
713
728
|
return NULL;
|
|
714
729
|
}
|
|
715
730
|
|
|
716
|
-
EXPORT int
|
|
731
|
+
EXPORT int CallThreaded(IntCallback *func, int x)
|
|
717
732
|
{
|
|
718
|
-
|
|
733
|
+
CallContext ctx;
|
|
719
734
|
|
|
720
|
-
|
|
735
|
+
ctx.callback = func ? func : callback;
|
|
736
|
+
ctx.ptr = &x;
|
|
737
|
+
|
|
738
|
+
pthread_t thread;
|
|
739
|
+
if (pthread_create(&thread, NULL, CallThreadedFunc, &ctx)) {
|
|
721
740
|
perror("pthread_create");
|
|
722
741
|
exit(1);
|
|
723
742
|
}
|
|
@@ -729,12 +748,6 @@ EXPORT int CallIndirectThreaded(int x)
|
|
|
729
748
|
|
|
730
749
|
#endif
|
|
731
750
|
|
|
732
|
-
EXPORT int CallDirectThreaded(IntCallback *func, int x)
|
|
733
|
-
{
|
|
734
|
-
callback = func;
|
|
735
|
-
return CallIndirectThreaded(x);
|
|
736
|
-
}
|
|
737
|
-
|
|
738
751
|
EXPORT void ReverseBytes(void *p, int len)
|
|
739
752
|
{
|
|
740
753
|
uint8_t *bytes = (uint8_t *)p;
|
|
File without changes
|
|
@@ -342,7 +342,7 @@ async function prepare() {
|
|
|
342
342
|
log(machine, `${suite} > Status`, chalk.bold.red(`[manual]`));
|
|
343
343
|
needed = true;
|
|
344
344
|
} else {
|
|
345
|
-
log(machine, `${suite} > Status`, chalk.bold.red(`[
|
|
345
|
+
log(machine, `${suite} > Status`, chalk.bold.red(`[missing]`));
|
|
346
346
|
needed = true;
|
|
347
347
|
}
|
|
348
348
|
}
|
|
@@ -494,6 +494,7 @@ async function prepare() {
|
|
|
494
494
|
fs.renameSync(dist_dir + '/src/koffi/LICENSE.txt', dist_dir + '/LICENSE.txt');
|
|
495
495
|
fs.renameSync(dist_dir + '/src/koffi/ChangeLog.md', dist_dir + '/ChangeLog.md');
|
|
496
496
|
fs.renameSync(dist_dir + '/web/koffi.dev', dist_dir + '/doc');
|
|
497
|
+
fs.rmdirSync(dist_dir + '/web');
|
|
497
498
|
}
|
|
498
499
|
|
|
499
500
|
return dist_dir;
|
|
@@ -514,6 +515,8 @@ function snapshot() {
|
|
|
514
515
|
} else if (parts[0] == 'src') {
|
|
515
516
|
return parts[1] == null || parts[1] == 'cnoke' ||
|
|
516
517
|
parts[1] == 'koffi';
|
|
518
|
+
} else if (parts[0] == 'tools') {
|
|
519
|
+
return parts[1] == null || parts[1] != 'qemu';
|
|
517
520
|
} else if (parts[0] == 'vendor') {
|
|
518
521
|
return parts[1] == null || parts[1] == 'brotli' ||
|
|
519
522
|
parts[1] == 'dragonbox' ||
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
|
4
|
+
# it under the terms of the GNU Affero General Public License as published by
|
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
6
|
+
# (at your option) any later version.
|
|
7
|
+
#
|
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11
|
+
# GNU Affero General Public License for more details.
|
|
12
|
+
#
|
|
13
|
+
# You should have received a copy of the GNU Affero General Public License
|
|
14
|
+
# along with this program. If not, see https://www.gnu.org/licenses/.
|
|
15
|
+
|
|
16
|
+
import argparse
|
|
17
|
+
import os
|
|
18
|
+
|
|
19
|
+
def write_asm_trampolines(filename, comment_char, n,
|
|
20
|
+
fmt_export, fmt_export_x, fmt_proc, fmt_proc_x, end = None):
|
|
21
|
+
with open(filename) as f:
|
|
22
|
+
lines = f.readlines()
|
|
23
|
+
|
|
24
|
+
with open(filename, 'w') as f:
|
|
25
|
+
for line in lines:
|
|
26
|
+
if line.rstrip() == comment_char + ' Trampolines':
|
|
27
|
+
break
|
|
28
|
+
f.write(line)
|
|
29
|
+
|
|
30
|
+
print(comment_char + ' Trampolines', file = f)
|
|
31
|
+
print(comment_char + ' ----------------------------', file = f)
|
|
32
|
+
print('', file = f)
|
|
33
|
+
|
|
34
|
+
for i in range(0, n):
|
|
35
|
+
print(fmt_export.format(i), file = f)
|
|
36
|
+
print('', file = f)
|
|
37
|
+
for i in range(0, n):
|
|
38
|
+
print(fmt_export_x.format(i), file = f)
|
|
39
|
+
print('', file = f)
|
|
40
|
+
|
|
41
|
+
for i in range(0, n):
|
|
42
|
+
print(fmt_proc.format(i), file = f)
|
|
43
|
+
print('', file = f)
|
|
44
|
+
for i in range(0, n):
|
|
45
|
+
print(fmt_proc_x.format(i), file = f)
|
|
46
|
+
|
|
47
|
+
if end is not None:
|
|
48
|
+
print('', file = f)
|
|
49
|
+
print(end, file = f)
|
|
50
|
+
|
|
51
|
+
def write_cxx_trampolines(filename, n):
|
|
52
|
+
with open(filename) as f:
|
|
53
|
+
lines = f.readlines()
|
|
54
|
+
|
|
55
|
+
with open(filename, 'w') as f:
|
|
56
|
+
for line in lines:
|
|
57
|
+
if not line.startswith('//'):
|
|
58
|
+
break
|
|
59
|
+
f.write(line)
|
|
60
|
+
|
|
61
|
+
print('', file = f)
|
|
62
|
+
for i in range(0, n):
|
|
63
|
+
print('extern "C" int Trampoline{0}; extern "C" int TrampolineX{0};'.format(i), file = f)
|
|
64
|
+
|
|
65
|
+
print('', file = f)
|
|
66
|
+
print('static void *const Trampolines[][2] = {', file = f)
|
|
67
|
+
for i in range(0, n):
|
|
68
|
+
if i + 1 < n:
|
|
69
|
+
print(' {{ &Trampoline{0}, &TrampolineX{0} }},'.format(i), file = f)
|
|
70
|
+
else:
|
|
71
|
+
print(' {{ &Trampoline{0}, &TrampolineX{0} }}'.format(i), file = f)
|
|
72
|
+
print('};', file = f)
|
|
73
|
+
print('RG_STATIC_ASSERT(RG_LEN(Trampolines) == MaxTrampolines);', file = f)
|
|
74
|
+
|
|
75
|
+
if __name__ == "__main__":
|
|
76
|
+
parser = argparse.ArgumentParser(description = 'Generate static trampolines')
|
|
77
|
+
parser.add_argument('n', metavar = 'n', type = int, help = 'Number of trampolines')
|
|
78
|
+
args = parser.parse_args()
|
|
79
|
+
|
|
80
|
+
src_dir = os.path.dirname(__file__) + '/../src'
|
|
81
|
+
|
|
82
|
+
write_asm_trampolines(src_dir + '/abi_arm32_fwd.S', '#', args.n,
|
|
83
|
+
'.global Trampoline{0}',
|
|
84
|
+
'.global TrampolineX{0}',
|
|
85
|
+
'Trampoline{0}:\n trampoline {0}',
|
|
86
|
+
'TrampolineX{0}:\n trampoline_vec {0}'
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
write_asm_trampolines(src_dir + '/abi_arm64_fwd.asm', ';', args.n,
|
|
90
|
+
' EXPORT Trampoline{0}',
|
|
91
|
+
' EXPORT TrampolineX{0}',
|
|
92
|
+
'Trampoline{0} PROC\n trampoline {0}\n ENDP',
|
|
93
|
+
'TrampolineX{0} PROC\n trampoline_vec {0}\n ENDP',
|
|
94
|
+
' END'
|
|
95
|
+
)
|
|
96
|
+
write_asm_trampolines(src_dir + '/abi_arm64_fwd.S', '#', args.n,
|
|
97
|
+
'.global SYMBOL(Trampoline{0})',
|
|
98
|
+
'.global SYMBOL(TrampolineX{0})',
|
|
99
|
+
'SYMBOL(Trampoline{0}):\n trampoline {0}',
|
|
100
|
+
'SYMBOL(TrampolineX{0}):\n trampoline_vec {0}'
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
write_asm_trampolines(src_dir + '/abi_riscv64_fwd.S', '#', args.n,
|
|
104
|
+
'.global Trampoline{0}',
|
|
105
|
+
'.global TrampolineX{0}',
|
|
106
|
+
'Trampoline{0}:\n trampoline {0}',
|
|
107
|
+
'TrampolineX{0}:\n trampoline_vec {0}'
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
write_asm_trampolines(src_dir + '/abi_x64_sysv_fwd.S', '#', args.n,
|
|
111
|
+
'.global SYMBOL(Trampoline{0})',
|
|
112
|
+
'.global SYMBOL(TrampolineX{0})',
|
|
113
|
+
'SYMBOL(Trampoline{0}):\n trampoline {0}',
|
|
114
|
+
'SYMBOL(TrampolineX{0}):\n trampoline_xmm {0}'
|
|
115
|
+
)
|
|
116
|
+
write_asm_trampolines(src_dir + '/abi_x64_win_fwd.asm', ';', args.n,
|
|
117
|
+
'public Trampoline{0}',
|
|
118
|
+
'public TrampolineX{0}',
|
|
119
|
+
'Trampoline{0} proc frame\n trampoline {0}\nTrampoline{0} endp',
|
|
120
|
+
'TrampolineX{0} proc frame\n trampoline_xmm {0}\nTrampolineX{0} endp',
|
|
121
|
+
'end'
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
write_asm_trampolines(src_dir + '/abi_x86_fwd.asm', ';', args.n,
|
|
125
|
+
'public Trampoline{0}',
|
|
126
|
+
'public TrampolineX{0}',
|
|
127
|
+
'Trampoline{0} proc\n trampoline {0}\nTrampoline{0} endp',
|
|
128
|
+
'TrampolineX{0} proc\n trampoline_x87 {0}\nTrampolineX{0} endp',
|
|
129
|
+
'end'
|
|
130
|
+
)
|
|
131
|
+
write_asm_trampolines(src_dir + '/abi_x86_fwd.S', '#', args.n,
|
|
132
|
+
'.global Trampoline{0}',
|
|
133
|
+
'.global TrampolineX{0}',
|
|
134
|
+
'Trampoline{0}:\n trampoline {0}',
|
|
135
|
+
'TrampolineX{0}:\n trampoline_x87 {0}'
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
write_cxx_trampolines(src_dir + '/abi_trampolines.inc', args.n)
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|