koffi 1.1.2 → 1.1.5
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 +23 -19
- package/README.md +16 -27
- package/benchmark/CMakeLists.txt +11 -3
- package/benchmark/raylib_cc.cc +9 -9
- package/build/qemu/1.1.5/koffi_darwin_x64.tar.gz +0 -0
- package/build/qemu/1.1.5/koffi_freebsd_arm64.tar.gz +0 -0
- package/build/qemu/1.1.5/koffi_freebsd_ia32.tar.gz +0 -0
- package/build/qemu/1.1.5/koffi_freebsd_x64.tar.gz +0 -0
- package/build/qemu/1.1.5/koffi_linux_arm.tar.gz +0 -0
- package/build/qemu/1.1.5/koffi_linux_arm64.tar.gz +0 -0
- package/build/qemu/1.1.5/koffi_linux_ia32.tar.gz +0 -0
- package/build/qemu/1.1.5/koffi_linux_riscv64.tar.gz +0 -0
- package/build/qemu/1.1.5/koffi_linux_x64.tar.gz +0 -0
- package/build/qemu/1.1.5/koffi_openbsd_ia32.tar.gz +0 -0
- package/build/qemu/1.1.5/koffi_openbsd_x64.tar.gz +0 -0
- package/build/qemu/1.1.5/koffi_win32_ia32.tar.gz +0 -0
- package/build/qemu/1.1.5/koffi_win32_x64.tar.gz +0 -0
- package/package.json +2 -2
- package/qemu/qemu.js +18 -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_arm32_fwd.S +1 -1
- package/src/abi_arm64.cc +33 -17
- package/src/abi_arm64_fwd.S +1 -1
- package/src/abi_arm64_fwd.asm +107 -0
- 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_sysv_fwd.S +113 -1
- package/src/abi_x64_win.cc +5 -8
- package/src/abi_x86.cc +11 -6
- package/src/call.cc +6 -18
- package/src/call.hh +13 -23
- package/src/ffi.cc +87 -25
- package/src/ffi.hh +14 -4
- package/src/parser.cc +18 -6
- package/src/util.cc +26 -57
- package/src/util.hh +17 -1
- package/test/CMakeLists.txt +4 -1
- 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.2/koffi_darwin_x64.tar.gz +0 -0
- package/build/qemu/1.1.2/koffi_freebsd_arm64.tar.gz +0 -0
- package/build/qemu/1.1.2/koffi_freebsd_ia32.tar.gz +0 -0
- package/build/qemu/1.1.2/koffi_freebsd_x64.tar.gz +0 -0
- package/build/qemu/1.1.2/koffi_linux_arm.tar.gz +0 -0
- package/build/qemu/1.1.2/koffi_linux_arm64.tar.gz +0 -0
- package/build/qemu/1.1.2/koffi_linux_ia32.tar.gz +0 -0
- package/build/qemu/1.1.2/koffi_linux_x64.tar.gz +0 -0
- package/build/qemu/1.1.2/koffi_win32_ia32.tar.gz +0 -0
- package/build/qemu/1.1.2/koffi_win32_x64.tar.gz +0 -0
package/src/abi_arm64.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(__aarch64__)
|
|
14
|
+
#if defined(__aarch64__) || defined(_M_ARM64)
|
|
15
15
|
|
|
16
16
|
#include "vendor/libcc/libcc.hh"
|
|
17
17
|
#include "ffi.hh"
|
|
@@ -41,10 +41,15 @@ extern "C" X0X1Ret ForwardCallXGG(const void *func, uint8_t *sp);
|
|
|
41
41
|
extern "C" float ForwardCallXF(const void *func, uint8_t *sp);
|
|
42
42
|
extern "C" HfaRet ForwardCallXDDDD(const void *func, uint8_t *sp);
|
|
43
43
|
|
|
44
|
+
static inline int IsHFA(const TypeInfo *type)
|
|
45
|
+
{
|
|
46
|
+
return IsHFA(type, 1, 4);
|
|
47
|
+
}
|
|
48
|
+
|
|
44
49
|
bool AnalyseFunction(InstanceData *, FunctionInfo *func)
|
|
45
50
|
{
|
|
46
|
-
if (IsHFA(func->ret.type
|
|
47
|
-
func->ret.vec_count =
|
|
51
|
+
if (int hfa = IsHFA(func->ret.type); hfa) {
|
|
52
|
+
func->ret.vec_count = hfa;
|
|
48
53
|
} else if (func->ret.type->size <= 16) {
|
|
49
54
|
func->ret.gpr_count = (func->ret.type->size + 7) / 8;
|
|
50
55
|
} else {
|
|
@@ -81,19 +86,23 @@ bool AnalyseFunction(InstanceData *, FunctionInfo *func)
|
|
|
81
86
|
}
|
|
82
87
|
} break;
|
|
83
88
|
case PrimitiveKind::Record: {
|
|
84
|
-
|
|
89
|
+
int hfa = IsHFA(param.type);
|
|
90
|
+
|
|
91
|
+
#if defined(_WIN32)
|
|
92
|
+
if (!param.variadic) {
|
|
93
|
+
hfa = 0;
|
|
94
|
+
}
|
|
95
|
+
#elif defined(__APPLE__)
|
|
85
96
|
if (param.variadic) {
|
|
86
97
|
param.use_memory = (param.type->size > 16);
|
|
87
98
|
break;
|
|
88
99
|
}
|
|
89
100
|
#endif
|
|
90
101
|
|
|
91
|
-
if (
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
param.vec_count = vec_count;
|
|
96
|
-
vec_avail -= vec_count;
|
|
102
|
+
if (hfa) {
|
|
103
|
+
if (hfa <= vec_avail) {
|
|
104
|
+
param.vec_count = hfa;
|
|
105
|
+
vec_avail -= hfa;
|
|
97
106
|
} else {
|
|
98
107
|
vec_avail = 0;
|
|
99
108
|
}
|
|
@@ -118,7 +127,15 @@ bool AnalyseFunction(InstanceData *, FunctionInfo *func)
|
|
|
118
127
|
case PrimitiveKind::Array: { RG_UNREACHABLE(); } break;
|
|
119
128
|
case PrimitiveKind::Float32:
|
|
120
129
|
case PrimitiveKind::Float64: {
|
|
121
|
-
#
|
|
130
|
+
#if defined(_WIN32)
|
|
131
|
+
if (param.variadic) {
|
|
132
|
+
if (gpr_avail) {
|
|
133
|
+
param.gpr_count = 1;
|
|
134
|
+
gpr_avail--;
|
|
135
|
+
}
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
#elif defined(__APPLE__)
|
|
122
139
|
if (param.variadic)
|
|
123
140
|
break;
|
|
124
141
|
#endif
|
|
@@ -378,8 +395,7 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
378
395
|
}
|
|
379
396
|
}
|
|
380
397
|
|
|
381
|
-
|
|
382
|
-
heap = MakeSpan(old_heap_mem.ptr, mem->heap.ptr - old_heap_mem.ptr);
|
|
398
|
+
sp = mem->stack.end();
|
|
383
399
|
|
|
384
400
|
return true;
|
|
385
401
|
}
|
|
@@ -388,8 +404,8 @@ void CallData::Execute()
|
|
|
388
404
|
{
|
|
389
405
|
#define PERFORM_CALL(Suffix) \
|
|
390
406
|
([&]() { \
|
|
391
|
-
auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func,
|
|
392
|
-
: ForwardCall ## Suffix(func->func,
|
|
407
|
+
auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, sp) \
|
|
408
|
+
: ForwardCall ## Suffix(func->func, sp)); \
|
|
393
409
|
return ret; \
|
|
394
410
|
})()
|
|
395
411
|
|
|
@@ -411,10 +427,10 @@ void CallData::Execute()
|
|
|
411
427
|
case PrimitiveKind::Record: {
|
|
412
428
|
if (func->ret.gpr_count) {
|
|
413
429
|
X0X1Ret ret = PERFORM_CALL(GG);
|
|
414
|
-
|
|
430
|
+
memcpy(&result.buf, &ret, RG_SIZE(ret));
|
|
415
431
|
} else if (func->ret.vec_count) {
|
|
416
432
|
HfaRet ret = PERFORM_CALL(DDDD);
|
|
417
|
-
|
|
433
|
+
memcpy(&result.buf, &ret, RG_SIZE(ret));
|
|
418
434
|
} else {
|
|
419
435
|
PERFORM_CALL(GG);
|
|
420
436
|
}
|
package/src/abi_arm64_fwd.S
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
8
8
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
9
9
|
// GNU Affero General Public License for more details.
|
|
10
|
-
|
|
10
|
+
//
|
|
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
|
|
|
@@ -0,0 +1,107 @@
|
|
|
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
|
+
AREA |.text|, CODE
|
|
15
|
+
|
|
16
|
+
; Copy function pointer to r9, in order to save it through argument forwarding.
|
|
17
|
+
; Save RSP in r29 (non-volatile), and use carefully assembled stack provided by caller.
|
|
18
|
+
MACRO
|
|
19
|
+
prologue
|
|
20
|
+
|
|
21
|
+
stp x29, x30, [sp, -16]!
|
|
22
|
+
mov x29, sp
|
|
23
|
+
mov x9, x0
|
|
24
|
+
add sp, x1, #136
|
|
25
|
+
MEND
|
|
26
|
+
|
|
27
|
+
; Call native function.
|
|
28
|
+
; Once done, restore normal stack pointer and return.
|
|
29
|
+
; The return value is passed untouched through r0, r1, v0 and/or v1.
|
|
30
|
+
MACRO
|
|
31
|
+
epilogue
|
|
32
|
+
|
|
33
|
+
blr x9
|
|
34
|
+
mov sp, x29
|
|
35
|
+
ldp x29, x30, [sp], 16
|
|
36
|
+
ret
|
|
37
|
+
MEND
|
|
38
|
+
|
|
39
|
+
; Prepare general purpose argument registers from array passed by caller.
|
|
40
|
+
MACRO
|
|
41
|
+
forward_int
|
|
42
|
+
|
|
43
|
+
ldr x8, [x1, 64]
|
|
44
|
+
ldr x7, [x1, 56]
|
|
45
|
+
ldr x6, [x1, 48]
|
|
46
|
+
ldr x5, [x1, 40]
|
|
47
|
+
ldr x4, [x1, 32]
|
|
48
|
+
ldr x3, [x1, 24]
|
|
49
|
+
ldr x2, [x1, 16]
|
|
50
|
+
ldr x0, [x1, 0]
|
|
51
|
+
ldr x1, [x1, 8]
|
|
52
|
+
MEND
|
|
53
|
+
|
|
54
|
+
; Prepare vector argument registers from array passed by caller.
|
|
55
|
+
MACRO
|
|
56
|
+
forward_vec
|
|
57
|
+
|
|
58
|
+
ldr d7, [x1, 128]
|
|
59
|
+
ldr d6, [x1, 120]
|
|
60
|
+
ldr d5, [x1, 112]
|
|
61
|
+
ldr d4, [x1, 104]
|
|
62
|
+
ldr d3, [x1, 96]
|
|
63
|
+
ldr d2, [x1, 88]
|
|
64
|
+
ldr d1, [x1, 80]
|
|
65
|
+
ldr d0, [x1, 72]
|
|
66
|
+
MEND
|
|
67
|
+
|
|
68
|
+
ForwardCallGG PROC
|
|
69
|
+
prologue
|
|
70
|
+
forward_int
|
|
71
|
+
epilogue
|
|
72
|
+
ENDP
|
|
73
|
+
|
|
74
|
+
ForwardCallF PROC
|
|
75
|
+
prologue
|
|
76
|
+
forward_int
|
|
77
|
+
epilogue
|
|
78
|
+
ENDP
|
|
79
|
+
|
|
80
|
+
ForwardCallDDDD PROC
|
|
81
|
+
prologue
|
|
82
|
+
forward_int
|
|
83
|
+
epilogue
|
|
84
|
+
ENDP
|
|
85
|
+
|
|
86
|
+
ForwardCallXGG PROC
|
|
87
|
+
prologue
|
|
88
|
+
forward_vec
|
|
89
|
+
forward_int
|
|
90
|
+
epilogue
|
|
91
|
+
ENDP
|
|
92
|
+
|
|
93
|
+
ForwardCallXF PROC
|
|
94
|
+
prologue
|
|
95
|
+
forward_vec
|
|
96
|
+
forward_int
|
|
97
|
+
epilogue
|
|
98
|
+
ENDP
|
|
99
|
+
|
|
100
|
+
ForwardCallXDDDD PROC
|
|
101
|
+
prologue
|
|
102
|
+
forward_vec
|
|
103
|
+
forward_int
|
|
104
|
+
epilogue
|
|
105
|
+
ENDP
|
|
106
|
+
|
|
107
|
+
END
|
|
@@ -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
|