koffi 1.3.5 → 1.3.8
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 +1 -1
- package/ChangeLog.md +36 -0
- package/benchmark/atoi_koffi.js +3 -4
- package/benchmark/atoi_napi.js +2 -3
- package/benchmark/atoi_node_ffi.js +3 -4
- package/benchmark/raylib_cc.cc +3 -4
- package/benchmark/raylib_cc.js +31 -0
- package/benchmark/raylib_koffi.js +8 -9
- package/benchmark/raylib_node_ffi.js +4 -5
- package/benchmark/raylib_node_raylib.js +4 -5
- package/build/qemu/1.3.8/koffi_darwin_arm64.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_darwin_x64.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_freebsd_arm64.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_freebsd_ia32.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_freebsd_x64.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_linux_arm32hf.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_linux_arm64.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_linux_ia32.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_linux_riscv64hf64.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_linux_x64.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_openbsd_ia32.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_openbsd_x64.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_win32_arm64.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_win32_ia32.tar.gz +0 -0
- package/build/qemu/1.3.8/koffi_win32_x64.tar.gz +0 -0
- package/doc/_static/perf_linux_20220627.png +0 -0
- package/doc/_static/perf_linux_20220628.png +0 -0
- package/doc/_static/perf_windows_20220627.png +0 -0
- package/doc/_static/perf_windows_20220628.png +0 -0
- package/doc/benchmarks.md +78 -58
- package/doc/benchmarks.xlsx +0 -0
- package/doc/conf.py +1 -1
- package/doc/contribute.md +8 -11
- package/doc/dist/html/_sources/benchmarks.md.txt +78 -58
- package/doc/dist/html/_sources/contribute.md.txt +8 -11
- package/doc/dist/html/_sources/functions.md.txt +9 -8
- package/doc/dist/html/_sources/index.rst.txt +3 -0
- package/doc/dist/html/_sources/platforms.md.txt +17 -5
- package/doc/dist/html/_sources/start.md.txt +14 -3
- package/doc/dist/html/_sources/types.md.txt +15 -11
- package/doc/dist/html/_static/basic.css +12 -14
- package/doc/dist/html/_static/perf_linux_20220627.png +0 -0
- package/doc/dist/html/_static/perf_linux_20220628.png +0 -0
- package/doc/dist/html/_static/perf_windows_20220627.png +0 -0
- package/doc/dist/html/_static/perf_windows_20220628.png +0 -0
- package/doc/dist/html/benchmarks.html +148 -159
- package/doc/dist/html/changes.html +44 -2
- package/doc/dist/html/contribute.html +30 -33
- package/doc/dist/html/functions.html +19 -18
- package/doc/dist/html/genindex.html +2 -2
- package/doc/dist/html/index.html +19 -10
- package/doc/dist/html/memory.html +2 -2
- package/doc/dist/html/objects.inv +0 -0
- package/doc/dist/html/platforms.html +44 -10
- package/doc/dist/html/search.html +2 -2
- package/doc/dist/html/searchindex.js +1 -1
- package/doc/dist/html/start.html +25 -12
- package/doc/dist/html/types.html +31 -11
- package/doc/functions.md +9 -8
- package/doc/index.rst +3 -0
- package/doc/platforms.md +17 -5
- package/doc/start.md +14 -3
- package/doc/types.md +15 -11
- package/package.json +7 -4
- package/qemu/qemu.js +30 -19
- package/qemu/registry/machines.json +19 -19
- package/qemu/registry/sha256sum.txt +5 -5
- package/src/abi_arm32.cc +9 -2
- package/src/abi_arm32_fwd.S +7 -7
- package/src/abi_arm64.cc +9 -2
- package/src/abi_arm64_fwd.S +11 -7
- package/src/abi_arm64_fwd.asm +7 -7
- package/src/abi_riscv64.cc +9 -2
- package/src/abi_riscv64_fwd.S +11 -11
- package/src/abi_x64_sysv.cc +9 -2
- package/src/abi_x64_sysv_fwd.S +11 -11
- package/src/abi_x64_win.cc +9 -2
- package/src/abi_x64_win_fwd.asm +7 -7
- package/src/abi_x86.cc +9 -2
- package/src/abi_x86_fwd.S +3 -0
- package/src/abi_x86_fwd.asm +3 -0
- package/src/call.cc +20 -10
- package/src/ffi.cc +17 -8
- package/src/ffi.hh +4 -3
- package/src/util.cc +1 -1
- package/test/async.js +1 -1
- package/test/callbacks.js +25 -2
- package/test/misc.c +57 -2
- package/test/raylib.js +4 -4
- package/test/sqlite.js +5 -5
- package/test/sync.js +22 -7
- package/build/qemu/1.3.5/koffi_darwin_arm64.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_darwin_x64.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_freebsd_arm64.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_freebsd_ia32.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_freebsd_x64.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_linux_arm32hf.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_linux_arm64.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_linux_ia32.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_linux_riscv64hf64.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_linux_x64.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_openbsd_ia32.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_openbsd_x64.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_win32_arm64.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_win32_ia32.tar.gz +0 -0
- package/build/qemu/1.3.5/koffi_win32_x64.tar.gz +0 -0
package/src/abi_x64_sysv_fwd.S
CHANGED
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
.endm
|
|
67
67
|
|
|
68
68
|
# Prepare integer argument registers from array passed by caller.
|
|
69
|
-
.macro
|
|
69
|
+
.macro forward_gpr
|
|
70
70
|
movq 40(%rsi), %r9
|
|
71
71
|
movq 32(%rsi), %r8
|
|
72
72
|
movq 24(%rsi), %rcx
|
|
@@ -89,66 +89,66 @@
|
|
|
89
89
|
|
|
90
90
|
SYMBOL(ForwardCallGG):
|
|
91
91
|
prologue
|
|
92
|
-
|
|
92
|
+
forward_gpr
|
|
93
93
|
movb $0, %al
|
|
94
94
|
epilogue
|
|
95
95
|
|
|
96
96
|
SYMBOL(ForwardCallF):
|
|
97
97
|
prologue
|
|
98
|
-
|
|
98
|
+
forward_gpr
|
|
99
99
|
movb $0, %al
|
|
100
100
|
epilogue
|
|
101
101
|
|
|
102
102
|
SYMBOL(ForwardCallDG):
|
|
103
103
|
prologue
|
|
104
|
-
|
|
104
|
+
forward_gpr
|
|
105
105
|
movb $0, %al
|
|
106
106
|
epilogue
|
|
107
107
|
|
|
108
108
|
SYMBOL(ForwardCallGD):
|
|
109
109
|
prologue
|
|
110
|
-
|
|
110
|
+
forward_gpr
|
|
111
111
|
movb $0, %al
|
|
112
112
|
epilogue
|
|
113
113
|
|
|
114
114
|
SYMBOL(ForwardCallDD):
|
|
115
115
|
prologue
|
|
116
|
-
|
|
116
|
+
forward_gpr
|
|
117
117
|
movb $0, %al
|
|
118
118
|
epilogue
|
|
119
119
|
|
|
120
120
|
SYMBOL(ForwardCallXGG):
|
|
121
121
|
prologue
|
|
122
122
|
forward_xmm
|
|
123
|
-
|
|
123
|
+
forward_gpr
|
|
124
124
|
movb $8, %al
|
|
125
125
|
epilogue
|
|
126
126
|
|
|
127
127
|
SYMBOL(ForwardCallXF):
|
|
128
128
|
prologue
|
|
129
129
|
forward_xmm
|
|
130
|
-
|
|
130
|
+
forward_gpr
|
|
131
131
|
movb $8, %al
|
|
132
132
|
epilogue
|
|
133
133
|
|
|
134
134
|
SYMBOL(ForwardCallXDG):
|
|
135
135
|
prologue
|
|
136
136
|
forward_xmm
|
|
137
|
-
|
|
137
|
+
forward_gpr
|
|
138
138
|
movb $8, %al
|
|
139
139
|
epilogue
|
|
140
140
|
|
|
141
141
|
SYMBOL(ForwardCallXGD):
|
|
142
142
|
prologue
|
|
143
143
|
forward_xmm
|
|
144
|
-
|
|
144
|
+
forward_gpr
|
|
145
145
|
movb $8, %al
|
|
146
146
|
epilogue
|
|
147
147
|
|
|
148
148
|
SYMBOL(ForwardCallXDD):
|
|
149
149
|
prologue
|
|
150
150
|
forward_xmm
|
|
151
|
-
|
|
151
|
+
forward_gpr
|
|
152
152
|
movb $8, %al
|
|
153
153
|
epilogue
|
|
154
154
|
|
package/src/abi_x64_win.cc
CHANGED
|
@@ -337,8 +337,15 @@ Napi::Value CallData::Complete()
|
|
|
337
337
|
|
|
338
338
|
void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
|
|
339
339
|
{
|
|
340
|
-
const
|
|
341
|
-
|
|
340
|
+
const TrampolineInfo &trampoline = instance->trampolines[idx];
|
|
341
|
+
|
|
342
|
+
if (RG_UNLIKELY(trampoline.generation != mem->generation)) {
|
|
343
|
+
ThrowError<Napi::Error>(env, "Cannot use non-persistent callback beyond FFI call");
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
const FunctionInfo *proto = trampoline.proto;
|
|
348
|
+
Napi::Function func = trampoline.func.Value();
|
|
342
349
|
|
|
343
350
|
uint64_t *gpr_ptr = (uint64_t *)own_sp;
|
|
344
351
|
uint64_t *xmm_ptr = gpr_ptr + 4;
|
package/src/abi_x64_win_fwd.asm
CHANGED
|
@@ -53,7 +53,7 @@ epilogue macro
|
|
|
53
53
|
endm
|
|
54
54
|
|
|
55
55
|
; Prepare integer argument registers from array passed by caller.
|
|
56
|
-
|
|
56
|
+
forward_gpr macro
|
|
57
57
|
mov r9, qword ptr [rdx+24]
|
|
58
58
|
mov r8, qword ptr [rdx+16]
|
|
59
59
|
mov rcx, qword ptr [rdx+0]
|
|
@@ -70,40 +70,40 @@ endm
|
|
|
70
70
|
|
|
71
71
|
ForwardCallG proc frame
|
|
72
72
|
prologue
|
|
73
|
-
|
|
73
|
+
forward_gpr
|
|
74
74
|
epilogue
|
|
75
75
|
ForwardCallG endp
|
|
76
76
|
|
|
77
77
|
ForwardCallF proc frame
|
|
78
78
|
prologue
|
|
79
|
-
|
|
79
|
+
forward_gpr
|
|
80
80
|
epilogue
|
|
81
81
|
ForwardCallF endp
|
|
82
82
|
|
|
83
83
|
ForwardCallD proc frame
|
|
84
84
|
prologue
|
|
85
|
-
|
|
85
|
+
forward_gpr
|
|
86
86
|
epilogue
|
|
87
87
|
ForwardCallD endp
|
|
88
88
|
|
|
89
89
|
ForwardCallXG proc frame
|
|
90
90
|
prologue
|
|
91
91
|
forward_xmm
|
|
92
|
-
|
|
92
|
+
forward_gpr
|
|
93
93
|
epilogue
|
|
94
94
|
ForwardCallXG endp
|
|
95
95
|
|
|
96
96
|
ForwardCallXF proc frame
|
|
97
97
|
prologue
|
|
98
98
|
forward_xmm
|
|
99
|
-
|
|
99
|
+
forward_gpr
|
|
100
100
|
epilogue
|
|
101
101
|
ForwardCallXF endp
|
|
102
102
|
|
|
103
103
|
ForwardCallXD proc frame
|
|
104
104
|
prologue
|
|
105
105
|
forward_xmm
|
|
106
|
-
|
|
106
|
+
forward_gpr
|
|
107
107
|
epilogue
|
|
108
108
|
ForwardCallXD endp
|
|
109
109
|
|
package/src/abi_x86.cc
CHANGED
|
@@ -411,8 +411,15 @@ Napi::Value CallData::Complete()
|
|
|
411
411
|
|
|
412
412
|
void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
|
|
413
413
|
{
|
|
414
|
-
const
|
|
415
|
-
|
|
414
|
+
const TrampolineInfo &trampoline = instance->trampolines[idx];
|
|
415
|
+
|
|
416
|
+
if (RG_UNLIKELY(trampoline.generation != mem->generation)) {
|
|
417
|
+
ThrowError<Napi::Error>(env, "Cannot use non-persistent callback beyond FFI call");
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
const FunctionInfo *proto = trampoline.proto;
|
|
422
|
+
Napi::Function func = trampoline.func.Value();
|
|
416
423
|
|
|
417
424
|
uint32_t *args_ptr = (uint32_t *)caller_sp;
|
|
418
425
|
|
package/src/abi_x86_fwd.S
CHANGED
|
@@ -124,6 +124,9 @@ ForwardCallRD:
|
|
|
124
124
|
# static trampoline ID, the current stack pointer, a pointer to the stack arguments of this call,
|
|
125
125
|
# and a pointer to a struct that will contain the result registers.
|
|
126
126
|
# After the call, simply load these registers from the output struct.
|
|
127
|
+
# Depending on ABI, call convention and return value size, we need to issue ret <something>. Since ret
|
|
128
|
+
# only takes an immediate value, and I prefer not to branch, the return address is moved instead according
|
|
129
|
+
# to BackRegisters::ret_pop before ret is issued.
|
|
127
130
|
.macro trampoline id
|
|
128
131
|
.cfi_startproc
|
|
129
132
|
.cfi_def_cfa esp, 4
|
package/src/abi_x86_fwd.asm
CHANGED
|
@@ -128,6 +128,9 @@ public CallSwitchStack
|
|
|
128
128
|
; static trampoline ID, the current stack pointer, a pointer to the stack arguments of this call,
|
|
129
129
|
; and a pointer to a struct that will contain the result registers.
|
|
130
130
|
; After the call, simply load these registers from the output struct.
|
|
131
|
+
; Depending on ABI, call convention and return value size, we need to issue ret <something>. Since ret
|
|
132
|
+
; only takes an immediate value, and I prefer not to branch, the return address is moved instead according
|
|
133
|
+
; to BackRegisters::ret_pop before ret is issued.
|
|
131
134
|
trampoline macro ID
|
|
132
135
|
endbr32
|
|
133
136
|
sub esp, 44
|
package/src/call.cc
CHANGED
|
@@ -24,6 +24,7 @@ CallData::CallData(Napi::Env env, InstanceData *instance, const FunctionInfo *fu
|
|
|
24
24
|
: env(env), instance(instance), func(func),
|
|
25
25
|
mem(mem), old_stack_mem(mem->stack), old_heap_mem(mem->heap)
|
|
26
26
|
{
|
|
27
|
+
mem->generation += !mem->depth;
|
|
27
28
|
mem->depth++;
|
|
28
29
|
|
|
29
30
|
RG_ASSERT(AlignUp(mem->stack.ptr, 16) == mem->stack.ptr);
|
|
@@ -226,25 +227,33 @@ bool CallData::PushObject(Napi::Object obj, const TypeInfo *type, uint8_t *origi
|
|
|
226
227
|
*(uint64_t *)dest = v;
|
|
227
228
|
} break;
|
|
228
229
|
case PrimitiveKind::String: {
|
|
229
|
-
|
|
230
|
+
const char *str;
|
|
231
|
+
if (RG_LIKELY(value.IsString())) {
|
|
232
|
+
str = PushString(value);
|
|
233
|
+
if (RG_UNLIKELY(!str))
|
|
234
|
+
return false;
|
|
235
|
+
} else if (IsNullOrUndefined(value)) {
|
|
236
|
+
str = nullptr;
|
|
237
|
+
} else {
|
|
230
238
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for member '%2', expected string", GetValueType(instance, value), member.name);
|
|
231
239
|
return false;
|
|
232
240
|
}
|
|
233
241
|
|
|
234
|
-
const char *str = PushString(value);
|
|
235
|
-
if (RG_UNLIKELY(!str))
|
|
236
|
-
return false;
|
|
237
242
|
*(const char **)dest = str;
|
|
238
243
|
} break;
|
|
239
244
|
case PrimitiveKind::String16: {
|
|
240
|
-
|
|
245
|
+
const char16_t *str16;
|
|
246
|
+
if (RG_LIKELY(value.IsString())) {
|
|
247
|
+
str16 = PushString16(value);
|
|
248
|
+
if (RG_UNLIKELY(!str16))
|
|
249
|
+
return false;
|
|
250
|
+
} else if (IsNullOrUndefined(value)) {
|
|
251
|
+
str16 = nullptr;
|
|
252
|
+
} else {
|
|
241
253
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for member '%2', expected string", GetValueType(instance, value), member.name);
|
|
242
254
|
return false;
|
|
243
255
|
}
|
|
244
256
|
|
|
245
|
-
const char16_t *str16 = PushString16(value);
|
|
246
|
-
if (RG_UNLIKELY(!str16))
|
|
247
|
-
return false;
|
|
248
257
|
*(const char16_t **)dest = str16;
|
|
249
258
|
} break;
|
|
250
259
|
case PrimitiveKind::Pointer: {
|
|
@@ -314,7 +323,7 @@ bool CallData::PushObject(Napi::Object obj, const TypeInfo *type, uint8_t *origi
|
|
|
314
323
|
if (value.IsFunction()) {
|
|
315
324
|
Napi::Function func = value.As<Napi::Function>();
|
|
316
325
|
|
|
317
|
-
ptr = ReserveTrampoline(type->proto, func);
|
|
326
|
+
ptr = ReserveTrampoline(member.type->proto, func);
|
|
318
327
|
if (RG_UNLIKELY(!ptr))
|
|
319
328
|
return false;
|
|
320
329
|
} else if (CheckValueTag(instance, value, member.type)) {
|
|
@@ -748,7 +757,8 @@ void *CallData::ReserveTrampoline(const FunctionInfo *proto, Napi::Function func
|
|
|
748
757
|
used_trampolines |= 1u << idx;
|
|
749
758
|
|
|
750
759
|
instance->trampolines[idx].proto = proto;
|
|
751
|
-
instance->trampolines[idx].func
|
|
760
|
+
instance->trampolines[idx].func.Reset(func, 1);
|
|
761
|
+
instance->trampolines[idx].generation = mem->generation;
|
|
752
762
|
|
|
753
763
|
void *trampoline = GetTrampoline(idx, proto);
|
|
754
764
|
return trampoline;
|
package/src/ffi.cc
CHANGED
|
@@ -550,7 +550,7 @@ static Napi::Value CreateCallbackType(const Napi::CallbackInfo &info)
|
|
|
550
550
|
if (!ParsePrototype(env, proto.c_str(), func))
|
|
551
551
|
return env.Null();
|
|
552
552
|
} else {
|
|
553
|
-
ThrowError<Napi::TypeError>(env, "Expected 1 or 3 arguments,
|
|
553
|
+
ThrowError<Napi::TypeError>(env, "Expected 1 or 3 arguments, got %1", info.Length());
|
|
554
554
|
return env.Null();
|
|
555
555
|
}
|
|
556
556
|
|
|
@@ -894,7 +894,7 @@ static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info, CallConve
|
|
|
894
894
|
if (!ParsePrototype(env, proto.c_str(), func))
|
|
895
895
|
return env.Null();
|
|
896
896
|
} else {
|
|
897
|
-
ThrowError<Napi::TypeError>(env, "Expected 1 or 3 arguments,
|
|
897
|
+
ThrowError<Napi::TypeError>(env, "Expected 1 or 3 arguments, got %1", info.Length());
|
|
898
898
|
return env.Null();
|
|
899
899
|
}
|
|
900
900
|
|
|
@@ -957,7 +957,7 @@ static Napi::Value LoadSharedLibrary(const Napi::CallbackInfo &info)
|
|
|
957
957
|
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
958
958
|
|
|
959
959
|
if (info.Length() < 1) {
|
|
960
|
-
ThrowError<Napi::TypeError>(env, "Expected 2 arguments,
|
|
960
|
+
ThrowError<Napi::TypeError>(env, "Expected 1 or 2 arguments, got %1", info.Length());
|
|
961
961
|
return env.Null();
|
|
962
962
|
}
|
|
963
963
|
if (!info[0].IsString() && !IsNullOrUndefined(info[0])) {
|
|
@@ -1075,9 +1075,12 @@ static void RegisterPrimitiveType(InstanceData *instance, const char *name, Prim
|
|
|
1075
1075
|
instance->types_map.Set(type);
|
|
1076
1076
|
}
|
|
1077
1077
|
|
|
1078
|
-
|
|
1078
|
+
template <typename T>
|
|
1079
|
+
static inline PrimitiveKind GetIntegerPrimitive(bool sign)
|
|
1079
1080
|
{
|
|
1080
|
-
switch (RG_SIZE(
|
|
1081
|
+
switch (RG_SIZE(T)) {
|
|
1082
|
+
case 1: return sign ? PrimitiveKind::Int8 : PrimitiveKind::UInt8;
|
|
1083
|
+
case 2: return sign ? PrimitiveKind::Int16 : PrimitiveKind::UInt16;
|
|
1081
1084
|
case 4: return sign ? PrimitiveKind::Int32 : PrimitiveKind::UInt32;
|
|
1082
1085
|
case 8: return sign ? PrimitiveKind::Int64 : PrimitiveKind::UInt64;
|
|
1083
1086
|
}
|
|
@@ -1121,9 +1124,13 @@ static Napi::Object InitBaseTypes(Napi::Env env)
|
|
|
1121
1124
|
RegisterPrimitiveType(instance, "int64_t", PrimitiveKind::Int64, 8, alignof(int64_t));
|
|
1122
1125
|
RegisterPrimitiveType(instance, "uint64", PrimitiveKind::UInt64, 8, alignof(int64_t));
|
|
1123
1126
|
RegisterPrimitiveType(instance, "uint64_t", PrimitiveKind::UInt64, 8, alignof(int64_t));
|
|
1124
|
-
RegisterPrimitiveType(instance, "
|
|
1125
|
-
RegisterPrimitiveType(instance, "
|
|
1126
|
-
RegisterPrimitiveType(instance, "
|
|
1127
|
+
RegisterPrimitiveType(instance, "intptr", GetIntegerPrimitive<intptr_t>(true), RG_SIZE(intptr_t), alignof(intptr_t));
|
|
1128
|
+
RegisterPrimitiveType(instance, "intptr_t", GetIntegerPrimitive<intptr_t>(true), RG_SIZE(intptr_t), alignof(intptr_t));
|
|
1129
|
+
RegisterPrimitiveType(instance, "uintptr", GetIntegerPrimitive<intptr_t>(false), RG_SIZE(intptr_t), alignof(intptr_t));
|
|
1130
|
+
RegisterPrimitiveType(instance, "uintptr_t", GetIntegerPrimitive<intptr_t>(false), RG_SIZE(intptr_t), alignof(intptr_t));
|
|
1131
|
+
RegisterPrimitiveType(instance, "long", GetIntegerPrimitive<long>(true), RG_SIZE(long), alignof(long));
|
|
1132
|
+
RegisterPrimitiveType(instance, "ulong", GetIntegerPrimitive<long>(false), RG_SIZE(long), alignof(long));
|
|
1133
|
+
RegisterPrimitiveType(instance, "unsigned long", GetIntegerPrimitive<long>(false), RG_SIZE(long), alignof(long));
|
|
1127
1134
|
RegisterPrimitiveType(instance, "longlong", PrimitiveKind::Int64, RG_SIZE(int64_t), alignof(int64_t));
|
|
1128
1135
|
RegisterPrimitiveType(instance, "long long", PrimitiveKind::Int64, RG_SIZE(int64_t), alignof(int64_t));
|
|
1129
1136
|
RegisterPrimitiveType(instance, "ulonglong", PrimitiveKind::UInt64, RG_SIZE(uint64_t), alignof(uint64_t));
|
|
@@ -1134,6 +1141,8 @@ static Napi::Object InitBaseTypes(Napi::Env env)
|
|
|
1134
1141
|
RegisterPrimitiveType(instance, "double", PrimitiveKind::Float64, 8, alignof(double));
|
|
1135
1142
|
RegisterPrimitiveType(instance, "string", PrimitiveKind::String, RG_SIZE(void *), alignof(void *));
|
|
1136
1143
|
RegisterPrimitiveType(instance, "string16", PrimitiveKind::String16, RG_SIZE(void *), alignof(void *));
|
|
1144
|
+
RegisterPrimitiveType(instance, "str", PrimitiveKind::String, RG_SIZE(void *), alignof(void *));
|
|
1145
|
+
RegisterPrimitiveType(instance, "str16", PrimitiveKind::String16, RG_SIZE(void *), alignof(void *));
|
|
1137
1146
|
|
|
1138
1147
|
Napi::Object types = Napi::Object::New(env);
|
|
1139
1148
|
for (TypeInfo &type: instance->types) {
|
package/src/ffi.hh
CHANGED
|
@@ -86,7 +86,6 @@ struct TypeInfo {
|
|
|
86
86
|
};
|
|
87
87
|
|
|
88
88
|
const char *name;
|
|
89
|
-
napi_type_tag tag;
|
|
90
89
|
|
|
91
90
|
Napi::ObjectReference defn;
|
|
92
91
|
|
|
@@ -199,13 +198,15 @@ struct InstanceMemory {
|
|
|
199
198
|
Span<uint8_t> stack;
|
|
200
199
|
Span<uint8_t> heap;
|
|
201
200
|
|
|
202
|
-
|
|
201
|
+
uint16_t generation; // Can wrap without risk
|
|
202
|
+
int16_t depth;
|
|
203
203
|
bool temporary;
|
|
204
204
|
};
|
|
205
205
|
|
|
206
206
|
struct TrampolineInfo {
|
|
207
207
|
const FunctionInfo *proto;
|
|
208
|
-
Napi::
|
|
208
|
+
Napi::FunctionReference func;
|
|
209
|
+
uint16_t generation;
|
|
209
210
|
};
|
|
210
211
|
|
|
211
212
|
struct InstanceData {
|
package/src/util.cc
CHANGED
|
@@ -28,7 +28,7 @@ const TypeInfo *ResolveType(const InstanceData *instance, Napi::Value value, int
|
|
|
28
28
|
const TypeInfo *type = instance->types_map.FindValue(str.c_str(), nullptr);
|
|
29
29
|
|
|
30
30
|
if (!type) {
|
|
31
|
-
ThrowError<Napi::TypeError>(value.Env(), "Unknown type
|
|
31
|
+
ThrowError<Napi::TypeError>(value.Env(), "Unknown type name '%1'", str.c_str());
|
|
32
32
|
return nullptr;
|
|
33
33
|
}
|
|
34
34
|
|
package/test/async.js
CHANGED
package/test/callbacks.js
CHANGED
|
@@ -21,7 +21,7 @@ const BFG = koffi.struct('BFG', {
|
|
|
21
21
|
a: 'int8_t',
|
|
22
22
|
b: 'int64_t',
|
|
23
23
|
c: 'char',
|
|
24
|
-
d: '
|
|
24
|
+
d: 'str',
|
|
25
25
|
e: 'short',
|
|
26
26
|
inner: koffi.struct({
|
|
27
27
|
f: 'float',
|
|
@@ -30,9 +30,16 @@ const BFG = koffi.struct('BFG', {
|
|
|
30
30
|
});
|
|
31
31
|
|
|
32
32
|
const SimpleCallback = koffi.callback('int SimpleCallback(const char *str)');
|
|
33
|
-
const RecursiveCallback = koffi.callback('RecursiveCallback', 'float', ['int', '
|
|
33
|
+
const RecursiveCallback = koffi.callback('RecursiveCallback', 'float', ['int', 'str', 'double']);
|
|
34
34
|
const BigCallback = koffi.callback('BFG BigCallback(BFG bfg)');
|
|
35
35
|
const ApplyCallback = koffi.callback('int __stdcall ApplyCallback(int a, int b, int c)');
|
|
36
|
+
const IntCallback = koffi.callback('int IntCallback(int x)');
|
|
37
|
+
|
|
38
|
+
const StructCallbacks = koffi.struct('StructCallbacks', {
|
|
39
|
+
first: IntCallback,
|
|
40
|
+
second: IntCallback,
|
|
41
|
+
third: IntCallback
|
|
42
|
+
});
|
|
36
43
|
|
|
37
44
|
main();
|
|
38
45
|
|
|
@@ -54,6 +61,8 @@ async function test() {
|
|
|
54
61
|
const CallRecursiveJS = lib.func('float CallRecursiveJS(int i, RecursiveCallback func)');
|
|
55
62
|
const ModifyBFG = lib.func('BFG ModifyBFG(int x, double y, const char *str, BigCallback func, _Out_ BFG *p)');
|
|
56
63
|
const ApplyStd = lib.func('int ApplyStd(int a, int b, int c, ApplyCallback func)');
|
|
64
|
+
const ApplyMany = lib.func('int ApplyMany(int x, IntCallback *funcs, int length)');
|
|
65
|
+
const ApplyStruct = lib.func('int ApplyStruct(int x, StructCallbacks callbacks)');
|
|
57
66
|
|
|
58
67
|
// Simple test similar to README example
|
|
59
68
|
{
|
|
@@ -92,4 +101,18 @@ async function test() {
|
|
|
92
101
|
let ret = ApplyStd(1, 5, 9, (a, b, c) => a + b * c);
|
|
93
102
|
assert.equal(ret, 46);
|
|
94
103
|
}
|
|
104
|
+
|
|
105
|
+
// Array of callbacks
|
|
106
|
+
{
|
|
107
|
+
let callbacks = [x => x * 5, x => x - 42, x => -x];
|
|
108
|
+
let ret = ApplyMany(27, callbacks, callbacks.length);
|
|
109
|
+
assert.equal(ret, -93);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Struct of callbacks
|
|
113
|
+
{
|
|
114
|
+
let callbacks = { first: x => -x, second: x => x * 5, third: x => x - 42 };
|
|
115
|
+
let ret = ApplyStruct(27, callbacks);
|
|
116
|
+
assert.equal(ret, -177);
|
|
117
|
+
}
|
|
95
118
|
}
|
package/test/misc.c
CHANGED
|
@@ -129,6 +129,20 @@ typedef struct IntContainer {
|
|
|
129
129
|
int len;
|
|
130
130
|
} IntContainer;
|
|
131
131
|
|
|
132
|
+
typedef struct StrStruct {
|
|
133
|
+
const char *str;
|
|
134
|
+
const char16_t *str16;
|
|
135
|
+
} StrStruct;
|
|
136
|
+
|
|
137
|
+
typedef int STDCALL ApplyCallback(int a, int b, int c);
|
|
138
|
+
typedef int IntCallback(int x);
|
|
139
|
+
|
|
140
|
+
typedef struct StructCallbacks {
|
|
141
|
+
IntCallback *first;
|
|
142
|
+
IntCallback *second;
|
|
143
|
+
IntCallback *third;
|
|
144
|
+
} StructCallbacks;
|
|
145
|
+
|
|
132
146
|
EXPORT int8_t GetMinusOne1(void)
|
|
133
147
|
{
|
|
134
148
|
return -1;
|
|
@@ -385,7 +399,12 @@ EXPORT PackedBFG FASTCALL MakePackedBFG(int x, double y, PackedBFG *p, const cha
|
|
|
385
399
|
return bfg;
|
|
386
400
|
}
|
|
387
401
|
|
|
402
|
+
#ifdef _WIN32
|
|
403
|
+
// Exported by DEF file
|
|
404
|
+
const char *ReturnBigString(const char *str)
|
|
405
|
+
#else
|
|
388
406
|
EXPORT const char *ReturnBigString(const char *str)
|
|
407
|
+
#endif
|
|
389
408
|
{
|
|
390
409
|
static char buf[16 * 1024 * 1024];
|
|
391
410
|
|
|
@@ -530,8 +549,6 @@ EXPORT BFG ModifyBFG(int x, double y, const char *str, BFG (*func)(BFG bfg), BFG
|
|
|
530
549
|
return bfg;
|
|
531
550
|
}
|
|
532
551
|
|
|
533
|
-
typedef int STDCALL ApplyCallback(int a, int b, int c);
|
|
534
|
-
|
|
535
552
|
EXPORT int ApplyStd(int a, int b, int c, ApplyCallback *func)
|
|
536
553
|
{
|
|
537
554
|
int ret = func(a, b, c);
|
|
@@ -563,3 +580,41 @@ EXPORT void MultiplyIntegers(int multiplier, int *values, int len)
|
|
|
563
580
|
values[i] *= multiplier;
|
|
564
581
|
}
|
|
565
582
|
}
|
|
583
|
+
|
|
584
|
+
EXPORT const char *ThroughStr(StrStruct s)
|
|
585
|
+
{
|
|
586
|
+
return s.str;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
EXPORT const char16_t *ThroughStr16(StrStruct s)
|
|
590
|
+
{
|
|
591
|
+
return s.str16;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
EXPORT const char *ThroughStrStar(StrStruct *s)
|
|
595
|
+
{
|
|
596
|
+
return s->str;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
EXPORT const char16_t *ThroughStrStar16(StrStruct *s)
|
|
600
|
+
{
|
|
601
|
+
return s->str16;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
EXPORT int ApplyMany(int x, IntCallback **callbacks, int length)
|
|
605
|
+
{
|
|
606
|
+
for (int i = 0; i < length; i++) {
|
|
607
|
+
x = (callbacks[i])(x);
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
return x;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
EXPORT int ApplyStruct(int x, StructCallbacks callbacks)
|
|
614
|
+
{
|
|
615
|
+
x = callbacks.first(x);
|
|
616
|
+
x = callbacks.second(x);
|
|
617
|
+
x = callbacks.third(x);
|
|
618
|
+
|
|
619
|
+
return x;
|
|
620
|
+
}
|
package/test/raylib.js
CHANGED
|
@@ -86,14 +86,14 @@ async function test() {
|
|
|
86
86
|
let lib_filename = path.dirname(__filename) + '/build/raylib' + koffi.extension;
|
|
87
87
|
let lib = koffi.load(lib_filename);
|
|
88
88
|
|
|
89
|
-
const InitWindow = lib.func('InitWindow', 'void', ['int', 'int', '
|
|
89
|
+
const InitWindow = lib.func('InitWindow', 'void', ['int', 'int', 'str']);
|
|
90
90
|
const SetTraceLogLevel = lib.func('SetTraceLogLevel', 'void', ['int']);
|
|
91
91
|
const SetWindowState = lib.func('SetWindowState', 'void', ['uint']);
|
|
92
92
|
const GenImageColor = lib.func('GenImageColor', Image, ['int', 'int', Color]);
|
|
93
93
|
const GetFontDefault = lib.func('GetFontDefault', Font, []);
|
|
94
|
-
const MeasureTextEx = lib.func('MeasureTextEx', Vector2, [Font, '
|
|
95
|
-
const ImageDrawTextEx = lib.func('ImageDrawTextEx', 'void', [koffi.pointer(Image), Font, '
|
|
96
|
-
const ExportImage = lib.func('ExportImage', 'bool', [Image, '
|
|
94
|
+
const MeasureTextEx = lib.func('MeasureTextEx', Vector2, [Font, 'str', 'float', 'float']);
|
|
95
|
+
const ImageDrawTextEx = lib.func('ImageDrawTextEx', 'void', [koffi.pointer(Image), Font, 'str', Vector2, 'float', 'float', Color]);
|
|
96
|
+
const ExportImage = lib.func('ExportImage', 'bool', [Image, 'str']);
|
|
97
97
|
|
|
98
98
|
// We need to call InitWindow before using anything else (such as fonts)
|
|
99
99
|
SetTraceLogLevel(4); // Warnings
|
package/test/sqlite.js
CHANGED
|
@@ -39,13 +39,13 @@ async function test() {
|
|
|
39
39
|
let lib_filename = path.dirname(__filename) + '/build/sqlite3' + koffi.extension;
|
|
40
40
|
let lib = koffi.load(lib_filename);
|
|
41
41
|
|
|
42
|
-
const sqlite3_open_v2 = lib.func('sqlite3_open_v2', 'int', ['
|
|
43
|
-
const sqlite3_exec = lib.func('sqlite3_exec', 'int', [sqlite3_db, '
|
|
44
|
-
const sqlite3_prepare_v2 = lib.func('sqlite3_prepare_v2', 'int', [sqlite3_db, '
|
|
42
|
+
const sqlite3_open_v2 = lib.func('sqlite3_open_v2', 'int', ['str', koffi.out(koffi.pointer(sqlite3_db)), 'int', 'str']);
|
|
43
|
+
const sqlite3_exec = lib.func('sqlite3_exec', 'int', [sqlite3_db, 'str', 'void *', 'void *', 'void *']);
|
|
44
|
+
const sqlite3_prepare_v2 = lib.func('sqlite3_prepare_v2', 'int', [sqlite3_db, 'str', 'int', koffi.out(koffi.pointer(sqlite3_stmt)), 'string']);
|
|
45
45
|
const sqlite3_reset = lib.func('sqlite3_reset', 'int', [sqlite3_stmt]);
|
|
46
|
-
const sqlite3_bind_text = lib.func('sqlite3_bind_text', 'int', [sqlite3_stmt, 'int', '
|
|
46
|
+
const sqlite3_bind_text = lib.func('sqlite3_bind_text', 'int', [sqlite3_stmt, 'int', 'str', 'int', 'void *']);
|
|
47
47
|
const sqlite3_bind_int = lib.func('sqlite3_bind_int', 'int', [sqlite3_stmt, 'int', 'int']);
|
|
48
|
-
const sqlite3_column_text = lib.func('sqlite3_column_text', '
|
|
48
|
+
const sqlite3_column_text = lib.func('sqlite3_column_text', 'str', [sqlite3_stmt, 'int']);
|
|
49
49
|
const sqlite3_column_int = lib.func('sqlite3_column_int', 'int', [sqlite3_stmt, 'int']);
|
|
50
50
|
const sqlite3_step = lib.func('sqlite3_step', 'int', [sqlite3_stmt]);
|
|
51
51
|
const sqlite3_finalize = lib.func('sqlite3_finalize', 'int', [sqlite3_stmt]);
|
package/test/sync.js
CHANGED
|
@@ -64,7 +64,7 @@ const BFG = koffi.struct('BFG', {
|
|
|
64
64
|
a: 'int8_t',
|
|
65
65
|
b: 'int64_t',
|
|
66
66
|
c: 'char',
|
|
67
|
-
d: '
|
|
67
|
+
d: 'str',
|
|
68
68
|
e: 'short',
|
|
69
69
|
inner: koffi.struct({
|
|
70
70
|
f: 'float',
|
|
@@ -75,7 +75,7 @@ const PackedBFG = koffi.pack('PackedBFG', {
|
|
|
75
75
|
a: 'int8_t',
|
|
76
76
|
b: 'int64_t',
|
|
77
77
|
c: 'char',
|
|
78
|
-
d: '
|
|
78
|
+
d: 'str',
|
|
79
79
|
e: 'short',
|
|
80
80
|
inner: koffi.pack({
|
|
81
81
|
f: 'float',
|
|
@@ -106,6 +106,11 @@ const IntContainer = koffi.struct('IntContainer', {
|
|
|
106
106
|
len: 'int'
|
|
107
107
|
});
|
|
108
108
|
|
|
109
|
+
const StrStruct = koffi.struct('StrStruct', {
|
|
110
|
+
str: 'str',
|
|
111
|
+
str16: 'str16'
|
|
112
|
+
});
|
|
113
|
+
|
|
109
114
|
main();
|
|
110
115
|
|
|
111
116
|
async function main() {
|
|
@@ -146,13 +151,13 @@ async function test() {
|
|
|
146
151
|
const ConcatenateToInt1 = lib.func('ConcatenateToInt1', 'int64_t', Array(12).fill('int8_t'));
|
|
147
152
|
const ConcatenateToInt4 = lib.func('ConcatenateToInt4', 'int64_t', Array(12).fill('int32_t'));
|
|
148
153
|
const ConcatenateToInt8 = lib.func('ConcatenateToInt8', 'int64_t', Array(12).fill('int64_t'));
|
|
149
|
-
const ConcatenateToStr1 = lib.func('ConcatenateToStr1', '
|
|
150
|
-
const ConcatenateToStr4 = lib.func('ConcatenateToStr4', '
|
|
151
|
-
const ConcatenateToStr8 = lib.func('ConcatenateToStr8', '
|
|
154
|
+
const ConcatenateToStr1 = lib.func('ConcatenateToStr1', 'str', [...Array(8).fill('int8_t'), koffi.struct('IJK1', {i: 'int8_t', j: 'int8_t', k: 'int8_t'}), 'int8_t']);
|
|
155
|
+
const ConcatenateToStr4 = lib.func('ConcatenateToStr4', 'str', [...Array(8).fill('int32_t'), koffi.pointer(koffi.struct('IJK4', {i: 'int32_t', j: 'int32_t', k: 'int32_t'})), 'int32_t']);
|
|
156
|
+
const ConcatenateToStr8 = lib.func('ConcatenateToStr8', 'str', [...Array(8).fill('int64_t'), koffi.struct('IJK8', {i: 'int64_t', j: 'int64_t', k: 'int64_t'}), 'int64_t']);
|
|
152
157
|
const MakeBFG = lib.func('BFG __stdcall MakeBFG(_Out_ BFG *p, int x, double y, const char *str)');
|
|
153
158
|
const MakePackedBFG = lib.func('PackedBFG __fastcall MakePackedBFG(int x, double y, _Out_ PackedBFG *p, const char *str)');
|
|
154
159
|
const ReturnBigString = process.platform == 'win32' ?
|
|
155
|
-
lib.stdcall(1, '
|
|
160
|
+
lib.stdcall(1, 'str', ['str']) :
|
|
156
161
|
lib.func('const char * __stdcall ReturnBigString(const char *str)');
|
|
157
162
|
const PrintFmt = lib.func('const char *PrintFmt(const char *fmt, ...)');
|
|
158
163
|
const Concat16 = lib.func('const char16_t *Concat16(const char16_t *str1, const char16_t *str2)')
|
|
@@ -175,6 +180,8 @@ async function test() {
|
|
|
175
180
|
const ArrayToStruct = lib.func('IntContainer ArrayToStruct(int *ptr, int len)');
|
|
176
181
|
const FillRange = lib.func('void FillRange(int init, int step, _Out_ int *out, int len)');
|
|
177
182
|
const MultiplyIntegers = lib.func('void MultiplyIntegers(int multiplier, _Inout_ int *values, int len)');
|
|
183
|
+
const ThroughStr = lib.func('str ThroughStr(StrStruct s)');
|
|
184
|
+
const ThroughStr16 = lib.func('str16 ThroughStr16(StrStruct s)');
|
|
178
185
|
|
|
179
186
|
// Simple signed value returns
|
|
180
187
|
assert.equal(GetMinusOne1(), -1);
|
|
@@ -292,7 +299,7 @@ async function test() {
|
|
|
292
299
|
|
|
293
300
|
// Variadic
|
|
294
301
|
{
|
|
295
|
-
let str = PrintFmt('foo %d %g %s', 'int', 200, 'double', 1.5, '
|
|
302
|
+
let str = PrintFmt('foo %d %g %s', 'int', 200, 'double', 1.5, 'str', 'BAR');
|
|
296
303
|
assert.equal(str, 'foo 200 1.5 BAR');
|
|
297
304
|
}
|
|
298
305
|
|
|
@@ -367,4 +374,12 @@ async function test() {
|
|
|
367
374
|
assert.deepEqual(out1, [-2, -9, -16, -23, -30, -37, -44, -51, 58, 65]);
|
|
368
375
|
assert.deepEqual(out2, new Int32Array([3 * 13, 3 * 16, 3 * 19, 3 * 22, 3 * 25, 3 * 28, 3 * 31, 34, 37, 40]));
|
|
369
376
|
}
|
|
377
|
+
|
|
378
|
+
// Test struct strings
|
|
379
|
+
{
|
|
380
|
+
assert.equal(ThroughStr({ str: 'Hello', str16: null }), 'Hello');
|
|
381
|
+
assert.equal(ThroughStr({ str: null, str16: 'Hello' }), null);
|
|
382
|
+
assert.equal(ThroughStr16({ str: null, str16: 'World!' }), 'World!');
|
|
383
|
+
assert.equal(ThroughStr16({ str: 'World!', str16: null }), null);
|
|
384
|
+
}
|
|
370
385
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|