koffi 0.9.0
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 +94 -0
- package/README.md +153 -0
- package/build/ALL_BUILD.vcxproj +190 -0
- package/build/ALL_BUILD.vcxproj.filters +8 -0
- package/build/CMakeCache.txt +429 -0
- package/build/CMakeFiles/3.23.0-rc1/CMakeASMCompiler.cmake +20 -0
- package/build/CMakeFiles/3.23.0-rc1/CMakeASM_MASMCompiler.cmake +20 -0
- package/build/CMakeFiles/3.23.0-rc1/CMakeCCompiler.cmake +72 -0
- package/build/CMakeFiles/3.23.0-rc1/CMakeCXXCompiler.cmake +83 -0
- package/build/CMakeFiles/3.23.0-rc1/CMakeDetermineCompilerABI_C.bin +0 -0
- package/build/CMakeFiles/3.23.0-rc1/CMakeDetermineCompilerABI_CXX.bin +0 -0
- package/build/CMakeFiles/3.23.0-rc1/CMakeRCCompiler.cmake +6 -0
- package/build/CMakeFiles/3.23.0-rc1/CMakeSystem.cmake +15 -0
- package/build/CMakeFiles/3.23.0-rc1/CompilerIdC/CMakeCCompilerId.c +828 -0
- package/build/CMakeFiles/3.23.0-rc1/CompilerIdC/CompilerIdC.exe +0 -0
- package/build/CMakeFiles/3.23.0-rc1/CompilerIdC/CompilerIdC.vcxproj +71 -0
- package/build/CMakeFiles/3.23.0-rc1/CompilerIdC/Debug/CMakeCCompilerId.obj +0 -0
- package/build/CMakeFiles/3.23.0-rc1/CompilerIdC/Debug/CompilerIdC.exe.recipe +11 -0
- package/build/CMakeFiles/3.23.0-rc1/CompilerIdC/Debug/CompilerIdC.tlog/CL.command.1.tlog +0 -0
- package/build/CMakeFiles/3.23.0-rc1/CompilerIdC/Debug/CompilerIdC.tlog/CL.read.1.tlog +0 -0
- package/build/CMakeFiles/3.23.0-rc1/CompilerIdC/Debug/CompilerIdC.tlog/CL.write.1.tlog +0 -0
- package/build/CMakeFiles/3.23.0-rc1/CompilerIdC/Debug/CompilerIdC.tlog/CompilerIdC.lastbuildstate +2 -0
- package/build/CMakeFiles/3.23.0-rc1/CompilerIdC/Debug/CompilerIdC.tlog/link.command.1.tlog +0 -0
- package/build/CMakeFiles/3.23.0-rc1/CompilerIdC/Debug/CompilerIdC.tlog/link.read.1.tlog +0 -0
- package/build/CMakeFiles/3.23.0-rc1/CompilerIdC/Debug/CompilerIdC.tlog/link.write.1.tlog +0 -0
- package/build/CMakeFiles/3.23.0-rc1/CompilerIdCXX/CMakeCXXCompilerId.cpp +816 -0
- package/build/CMakeFiles/3.23.0-rc1/CompilerIdCXX/CompilerIdCXX.exe +0 -0
- package/build/CMakeFiles/3.23.0-rc1/CompilerIdCXX/CompilerIdCXX.vcxproj +71 -0
- package/build/CMakeFiles/3.23.0-rc1/CompilerIdCXX/Debug/CMakeCXXCompilerId.obj +0 -0
- package/build/CMakeFiles/3.23.0-rc1/CompilerIdCXX/Debug/CompilerIdCXX.exe.recipe +11 -0
- package/build/CMakeFiles/3.23.0-rc1/CompilerIdCXX/Debug/CompilerIdCXX.tlog/CL.command.1.tlog +0 -0
- package/build/CMakeFiles/3.23.0-rc1/CompilerIdCXX/Debug/CompilerIdCXX.tlog/CL.read.1.tlog +0 -0
- package/build/CMakeFiles/3.23.0-rc1/CompilerIdCXX/Debug/CompilerIdCXX.tlog/CL.write.1.tlog +0 -0
- package/build/CMakeFiles/3.23.0-rc1/CompilerIdCXX/Debug/CompilerIdCXX.tlog/CompilerIdCXX.lastbuildstate +2 -0
- package/build/CMakeFiles/3.23.0-rc1/CompilerIdCXX/Debug/CompilerIdCXX.tlog/link.command.1.tlog +0 -0
- package/build/CMakeFiles/3.23.0-rc1/CompilerIdCXX/Debug/CompilerIdCXX.tlog/link.read.1.tlog +0 -0
- package/build/CMakeFiles/3.23.0-rc1/CompilerIdCXX/Debug/CompilerIdCXX.tlog/link.write.1.tlog +0 -0
- package/build/CMakeFiles/3.23.0-rc1/VCTargetsPath.txt +1 -0
- package/build/CMakeFiles/3.23.0-rc1/VCTargetsPath.vcxproj +31 -0
- package/build/CMakeFiles/3.23.0-rc1/x64/Debug/VCTargetsPath.recipe +11 -0
- package/build/CMakeFiles/3.23.0-rc1/x64/Debug/VCTargetsPath.tlog/VCTargetsPath.lastbuildstate +2 -0
- package/build/CMakeFiles/41bcd16856091d4a38fd1f71fbe2f202/generate.stamp.rule +1 -0
- package/build/CMakeFiles/CMakeError.log +108 -0
- package/build/CMakeFiles/CMakeOutput.log +413 -0
- package/build/CMakeFiles/TargetDirectories.txt +4 -0
- package/build/CMakeFiles/cmake.check_cache +1 -0
- package/build/CMakeFiles/generate.stamp +1 -0
- package/build/CMakeFiles/generate.stamp.depend +28 -0
- package/build/CMakeFiles/generate.stamp.list +1 -0
- package/build/Raylib.dir/Release/Raylib.dll.recipe +14 -0
- package/build/Raylib.dir/Release/Raylib.tlog/CL.command.1.tlog +0 -0
- package/build/Raylib.dir/Release/Raylib.tlog/CL.read.1.tlog +0 -0
- package/build/Raylib.dir/Release/Raylib.tlog/CL.write.1.tlog +0 -0
- package/build/Raylib.dir/Release/Raylib.tlog/CustomBuild.command.1.tlog +10 -0
- package/build/Raylib.dir/Release/Raylib.tlog/CustomBuild.read.1.tlog +27 -0
- package/build/Raylib.dir/Release/Raylib.tlog/CustomBuild.write.1.tlog +2 -0
- package/build/Raylib.dir/Release/Raylib.tlog/Raylib.lastbuildstate +2 -0
- package/build/Raylib.dir/Release/Raylib.tlog/Raylib.write.1u.tlog +0 -0
- package/build/Raylib.dir/Release/Raylib.tlog/link.command.1.tlog +0 -0
- package/build/Raylib.dir/Release/Raylib.tlog/link.read.1.tlog +0 -0
- package/build/Raylib.dir/Release/Raylib.tlog/link.write.1.tlog +0 -0
- package/build/Raylib.dir/Release/raudio.obj +0 -0
- package/build/Raylib.dir/Release/rcore.obj +0 -0
- package/build/Raylib.dir/Release/rglfw.obj +0 -0
- package/build/Raylib.dir/Release/rmodels.obj +0 -0
- package/build/Raylib.dir/Release/rshapes.obj +0 -0
- package/build/Raylib.dir/Release/rtext.obj +0 -0
- package/build/Raylib.dir/Release/rtextures.obj +0 -0
- package/build/Raylib.dir/Release/utils.obj +0 -0
- package/build/Raylib.vcxproj +358 -0
- package/build/Raylib.vcxproj.filters +37 -0
- package/build/Release/Raylib.dll +0 -0
- package/build/Release/Raylib.exp +0 -0
- package/build/Release/Raylib.lib +0 -0
- package/build/Release/koffi.exp +0 -0
- package/build/Release/koffi.lib +0 -0
- package/build/Release/koffi.node +0 -0
- package/build/ZERO_CHECK.vcxproj +176 -0
- package/build/ZERO_CHECK.vcxproj.filters +13 -0
- package/build/cmake_install.cmake +44 -0
- package/build/koffi.dir/Release/call_arm64.obj +0 -0
- package/build/koffi.dir/Release/call_x64_sysv.obj +0 -0
- package/build/koffi.dir/Release/call_x64_win.obj +0 -0
- package/build/koffi.dir/Release/call_x64_win_fwd.obj +0 -0
- package/build/koffi.dir/Release/call_x86.obj +0 -0
- package/build/koffi.dir/Release/ffi.obj +0 -0
- package/build/koffi.dir/Release/koffi.node.recipe +14 -0
- package/build/koffi.dir/Release/koffi.tlog/CL.command.1.tlog +0 -0
- package/build/koffi.dir/Release/koffi.tlog/CL.read.1.tlog +0 -0
- package/build/koffi.dir/Release/koffi.tlog/CL.write.1.tlog +0 -0
- package/build/koffi.dir/Release/koffi.tlog/CustomBuild.command.1.tlog +10 -0
- package/build/koffi.dir/Release/koffi.tlog/CustomBuild.read.1.tlog +27 -0
- package/build/koffi.dir/Release/koffi.tlog/CustomBuild.write.1.tlog +2 -0
- package/build/koffi.dir/Release/koffi.tlog/Masm.read.1u.tlog +0 -0
- package/build/koffi.dir/Release/koffi.tlog/Masm.write.1u.tlog +0 -0
- package/build/koffi.dir/Release/koffi.tlog/koffi.lastbuildstate +2 -0
- package/build/koffi.dir/Release/koffi.tlog/koffi.write.1u.tlog +0 -0
- package/build/koffi.dir/Release/koffi.tlog/link.command.1.tlog +0 -0
- package/build/koffi.dir/Release/koffi.tlog/link.read.1.tlog +0 -0
- package/build/koffi.dir/Release/koffi.tlog/link.write.1.tlog +0 -0
- package/build/koffi.dir/Release/libcc.obj +0 -0
- package/build/koffi.dir/Release/util.obj +0 -0
- package/build/koffi.dir/Release/win_delay_load_hook.obj +0 -0
- package/build/koffi.sln +67 -0
- package/build/koffi.vcxproj +363 -0
- package/build/koffi.vcxproj.filters +40 -0
- package/build/x64/Release/ALL_BUILD/ALL_BUILD.recipe +20 -0
- package/build/x64/Release/ALL_BUILD/ALL_BUILD.tlog/ALL_BUILD.lastbuildstate +2 -0
- package/build/x64/Release/ALL_BUILD/ALL_BUILD.tlog/CustomBuild.command.1.tlog +10 -0
- package/build/x64/Release/ALL_BUILD/ALL_BUILD.tlog/CustomBuild.read.1.tlog +27 -0
- package/build/x64/Release/ALL_BUILD/ALL_BUILD.tlog/CustomBuild.write.1.tlog +2 -0
- package/build/x64/Release/ZERO_CHECK/ZERO_CHECK.recipe +11 -0
- package/build/x64/Release/ZERO_CHECK/ZERO_CHECK.tlog/CustomBuild.command.1.tlog +10 -0
- package/build/x64/Release/ZERO_CHECK/ZERO_CHECK.tlog/CustomBuild.read.1.tlog +28 -0
- package/build/x64/Release/ZERO_CHECK/ZERO_CHECK.tlog/CustomBuild.write.1.tlog +2 -0
- package/build/x64/Release/ZERO_CHECK/ZERO_CHECK.tlog/ZERO_CHECK.lastbuildstate +2 -0
- package/package.json +14 -0
- package/src/call.hh +27 -0
- package/src/call_arm64.cc +482 -0
- package/src/call_arm64_fwd.S +115 -0
- package/src/call_x64_sysv.cc +477 -0
- package/src/call_x64_sysv_fwd.S +131 -0
- package/src/call_x64_win.cc +243 -0
- package/src/call_x64_win_fwd.asm +105 -0
- package/src/call_x86.cc +259 -0
- package/src/call_x86_fwd.S +48 -0
- package/src/call_x86_fwd.asm +50 -0
- package/src/ffi.cc +504 -0
- package/src/ffi.hh +135 -0
- package/src/util.cc +296 -0
- package/src/util.hh +80 -0
|
@@ -0,0 +1,477 @@
|
|
|
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 defined(__x86_64__) && !defined(_WIN64)
|
|
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
|
+
enum class RegisterClass {
|
|
26
|
+
NoClass = 0, // Explicitly 0
|
|
27
|
+
Integer,
|
|
28
|
+
SSE,
|
|
29
|
+
Memory
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
struct RaxRdxRet {
|
|
33
|
+
uint64_t rax;
|
|
34
|
+
uint64_t rdx;
|
|
35
|
+
};
|
|
36
|
+
struct RaxXmm0Ret {
|
|
37
|
+
uint64_t rax;
|
|
38
|
+
double xmm0;
|
|
39
|
+
};
|
|
40
|
+
struct Xmm0RaxRet {
|
|
41
|
+
double xmm0;
|
|
42
|
+
uint64_t rax;
|
|
43
|
+
};
|
|
44
|
+
struct Xmm0Xmm1Ret {
|
|
45
|
+
double xmm0;
|
|
46
|
+
double xmm1;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
extern "C" RaxRdxRet ForwardCallGG(const void *func, uint8_t *sp);
|
|
50
|
+
extern "C" float ForwardCallF(const void *func, uint8_t *sp);
|
|
51
|
+
extern "C" Xmm0RaxRet ForwardCallDG(const void *func, uint8_t *sp);
|
|
52
|
+
extern "C" RaxXmm0Ret ForwardCallGD(const void *func, uint8_t *sp);
|
|
53
|
+
extern "C" Xmm0Xmm1Ret ForwardCallDD(const void *func, uint8_t *sp);
|
|
54
|
+
|
|
55
|
+
extern "C" RaxRdxRet ForwardCallXGG(const void *func, uint8_t *sp);
|
|
56
|
+
extern "C" float ForwardCallXF(const void *func, uint8_t *sp);
|
|
57
|
+
extern "C" Xmm0RaxRet ForwardCallXDG(const void *func, uint8_t *sp);
|
|
58
|
+
extern "C" RaxXmm0Ret ForwardCallXGD(const void *func, uint8_t *sp);
|
|
59
|
+
extern "C" Xmm0Xmm1Ret ForwardCallXDD(const void *func, uint8_t *sp);
|
|
60
|
+
|
|
61
|
+
static inline RegisterClass MergeClasses(RegisterClass cls1, RegisterClass cls2)
|
|
62
|
+
{
|
|
63
|
+
if (cls1 == cls2)
|
|
64
|
+
return cls1;
|
|
65
|
+
|
|
66
|
+
if (cls1 == RegisterClass::NoClass)
|
|
67
|
+
return cls2;
|
|
68
|
+
if (cls2 == RegisterClass::NoClass)
|
|
69
|
+
return cls1;
|
|
70
|
+
|
|
71
|
+
if (cls1 == RegisterClass::Memory || cls2 == RegisterClass::Memory)
|
|
72
|
+
return RegisterClass::Memory;
|
|
73
|
+
if (cls1 == RegisterClass::Integer || cls2 == RegisterClass::Integer)
|
|
74
|
+
return RegisterClass::Integer;
|
|
75
|
+
|
|
76
|
+
return RegisterClass::SSE;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
static Size ClassifyType(const TypeInfo *type, Size offset, Span<RegisterClass> classes)
|
|
80
|
+
{
|
|
81
|
+
RG_ASSERT(classes.len > 0);
|
|
82
|
+
|
|
83
|
+
switch (type->primitive) {
|
|
84
|
+
case PrimitiveKind::Void: { return 0; } break;
|
|
85
|
+
|
|
86
|
+
case PrimitiveKind::Bool:
|
|
87
|
+
case PrimitiveKind::Int8:
|
|
88
|
+
case PrimitiveKind::UInt8:
|
|
89
|
+
case PrimitiveKind::Int16:
|
|
90
|
+
case PrimitiveKind::UInt16:
|
|
91
|
+
case PrimitiveKind::Int32:
|
|
92
|
+
case PrimitiveKind::UInt32:
|
|
93
|
+
case PrimitiveKind::Int64:
|
|
94
|
+
case PrimitiveKind::UInt64:
|
|
95
|
+
case PrimitiveKind::String:
|
|
96
|
+
case PrimitiveKind::Pointer: {
|
|
97
|
+
classes[0] = MergeClasses(classes[0], RegisterClass::Integer);
|
|
98
|
+
return 1;
|
|
99
|
+
} break;
|
|
100
|
+
|
|
101
|
+
case PrimitiveKind::Float32:
|
|
102
|
+
case PrimitiveKind::Float64: {
|
|
103
|
+
classes[0] = MergeClasses(classes[0], RegisterClass::SSE);
|
|
104
|
+
return 1;
|
|
105
|
+
} break;
|
|
106
|
+
|
|
107
|
+
case PrimitiveKind::Record: {
|
|
108
|
+
if (type->size > 64) {
|
|
109
|
+
classes[0] = MergeClasses(classes[0], RegisterClass::Memory);
|
|
110
|
+
return 1;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
for (const RecordMember &member: type->members) {
|
|
114
|
+
Size start = offset / 8;
|
|
115
|
+
ClassifyType(member.type, offset % 8, classes.Take(start, classes.len - start));
|
|
116
|
+
offset += member.type->size;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return (offset + 7) / 8;
|
|
120
|
+
} break;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
RG_UNREACHABLE();
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
static void AnalyseParameter(ParameterInfo *param, int gpr_avail, int xmm_avail)
|
|
127
|
+
{
|
|
128
|
+
LocalArray<RegisterClass, 8> classes = {};
|
|
129
|
+
classes.len = ClassifyType(param->type, 0, classes.data);
|
|
130
|
+
|
|
131
|
+
if (!classes.len)
|
|
132
|
+
return;
|
|
133
|
+
if (classes.len > 2) {
|
|
134
|
+
param->use_memory = true;
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
int gpr_count = 0;
|
|
139
|
+
int xmm_count = 0;
|
|
140
|
+
|
|
141
|
+
for (RegisterClass cls: classes) {
|
|
142
|
+
RG_ASSERT(cls != RegisterClass::NoClass);
|
|
143
|
+
|
|
144
|
+
if (cls == RegisterClass::Memory) {
|
|
145
|
+
param->use_memory = true;
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
gpr_count += (cls == RegisterClass::Integer);
|
|
150
|
+
xmm_count += (cls == RegisterClass::SSE);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (gpr_count <= gpr_avail && xmm_count <= xmm_avail){
|
|
154
|
+
param->gpr_count = (int8_t)gpr_count;
|
|
155
|
+
param->xmm_count = (int8_t)xmm_count;
|
|
156
|
+
param->gpr_first = (classes[0] == RegisterClass::Integer);
|
|
157
|
+
} else {
|
|
158
|
+
param->use_memory = true;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
bool AnalyseFunction(FunctionInfo *func)
|
|
163
|
+
{
|
|
164
|
+
AnalyseParameter(&func->ret, 2, 2);
|
|
165
|
+
|
|
166
|
+
int gpr_avail = 6 - func->ret.use_memory;
|
|
167
|
+
int xmm_avail = 8;
|
|
168
|
+
|
|
169
|
+
for (ParameterInfo ¶m: func->parameters) {
|
|
170
|
+
AnalyseParameter(¶m, gpr_avail, xmm_avail);
|
|
171
|
+
|
|
172
|
+
gpr_avail -= param.gpr_count;
|
|
173
|
+
xmm_avail -= param.xmm_count;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
func->forward_fp = (xmm_avail < 8);
|
|
177
|
+
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
Napi::Value TranslateCall(const Napi::CallbackInfo &info)
|
|
182
|
+
{
|
|
183
|
+
Napi::Env env = info.Env();
|
|
184
|
+
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
185
|
+
|
|
186
|
+
FunctionInfo *func = (FunctionInfo *)info.Data();
|
|
187
|
+
LibraryData *lib = func->lib.get();
|
|
188
|
+
|
|
189
|
+
RG_DEFER { lib->tmp_alloc.ReleaseAll(); };
|
|
190
|
+
|
|
191
|
+
// Sanity checks
|
|
192
|
+
if (info.Length() < (uint32_t)func->parameters.len) {
|
|
193
|
+
ThrowError<Napi::TypeError>(env, "Expected %1 arguments, got %2", func->parameters.len, info.Length());
|
|
194
|
+
return env.Null();
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Stack pointer and register
|
|
198
|
+
uint8_t *top_ptr = lib->stack.end();
|
|
199
|
+
uint8_t *return_ptr = nullptr;
|
|
200
|
+
uint8_t *args_ptr = nullptr;
|
|
201
|
+
uint64_t *gpr_ptr = nullptr, *xmm_ptr = nullptr;
|
|
202
|
+
uint8_t *sp_ptr = nullptr;
|
|
203
|
+
|
|
204
|
+
// Return through registers unless it's too big
|
|
205
|
+
if (!func->ret.use_memory) {
|
|
206
|
+
args_ptr = top_ptr - func->scratch_size;
|
|
207
|
+
xmm_ptr = (uint64_t *)args_ptr - 8;
|
|
208
|
+
gpr_ptr = xmm_ptr - 6;
|
|
209
|
+
sp_ptr = (uint8_t *)gpr_ptr;
|
|
210
|
+
|
|
211
|
+
#ifdef RG_DEBUG
|
|
212
|
+
memset(sp_ptr, 0, top_ptr - sp_ptr);
|
|
213
|
+
#endif
|
|
214
|
+
} else {
|
|
215
|
+
return_ptr = top_ptr - AlignLen(func->ret.type->size, 16);
|
|
216
|
+
|
|
217
|
+
args_ptr = return_ptr - func->scratch_size;
|
|
218
|
+
xmm_ptr = (uint64_t *)args_ptr - 8;
|
|
219
|
+
gpr_ptr = xmm_ptr - 6;
|
|
220
|
+
sp_ptr = (uint8_t *)gpr_ptr;
|
|
221
|
+
|
|
222
|
+
#ifdef RG_DEBUG
|
|
223
|
+
memset(sp_ptr, 0, top_ptr - sp_ptr);
|
|
224
|
+
#endif
|
|
225
|
+
|
|
226
|
+
*(gpr_ptr++) = (uint64_t)return_ptr;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
RG_ASSERT(AlignUp(lib->stack.ptr, 16) == lib->stack.ptr);
|
|
230
|
+
RG_ASSERT(AlignUp(lib->stack.end(), 16) == lib->stack.end());
|
|
231
|
+
RG_ASSERT(AlignUp(args_ptr, 16) == args_ptr);
|
|
232
|
+
|
|
233
|
+
// Push arguments
|
|
234
|
+
for (Size i = 0; i < func->parameters.len; i++) {
|
|
235
|
+
const ParameterInfo ¶m = func->parameters[i];
|
|
236
|
+
Napi::Value value = info[i];
|
|
237
|
+
|
|
238
|
+
switch (param.type->primitive) {
|
|
239
|
+
case PrimitiveKind::Void: { RG_UNREACHABLE(); } break;
|
|
240
|
+
|
|
241
|
+
case PrimitiveKind::Bool: {
|
|
242
|
+
if (RG_UNLIKELY(!value.IsBoolean())) {
|
|
243
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argmument %2, expected boolean", GetValueType(instance, value), i + 1);
|
|
244
|
+
return env.Null();
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
bool b = value.As<Napi::Boolean>();
|
|
248
|
+
|
|
249
|
+
if (RG_LIKELY(param.gpr_count)) {
|
|
250
|
+
*(gpr_ptr++) = (uint64_t)b;
|
|
251
|
+
} else {
|
|
252
|
+
*(args_ptr++) = (uint8_t)b;
|
|
253
|
+
}
|
|
254
|
+
} break;
|
|
255
|
+
case PrimitiveKind::Int8:
|
|
256
|
+
case PrimitiveKind::UInt8:
|
|
257
|
+
case PrimitiveKind::Int16:
|
|
258
|
+
case PrimitiveKind::UInt16:
|
|
259
|
+
case PrimitiveKind::Int32:
|
|
260
|
+
case PrimitiveKind::UInt32:
|
|
261
|
+
case PrimitiveKind::Int64:
|
|
262
|
+
case PrimitiveKind::UInt64: {
|
|
263
|
+
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
264
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
|
|
265
|
+
return env.Null();
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
int64_t v = CopyNodeNumber<int64_t>(value);
|
|
269
|
+
|
|
270
|
+
if (RG_LIKELY(param.gpr_count)) {
|
|
271
|
+
*(gpr_ptr++) = (uint64_t)v;
|
|
272
|
+
} else {
|
|
273
|
+
args_ptr = AlignUp(args_ptr, param.type->align);
|
|
274
|
+
memcpy(args_ptr, &v, param.type->size); // Little Endian
|
|
275
|
+
args_ptr += param.type->size;
|
|
276
|
+
}
|
|
277
|
+
} break;
|
|
278
|
+
case PrimitiveKind::Float32: {
|
|
279
|
+
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
280
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
|
|
281
|
+
return env.Null();
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
float f = CopyNodeNumber<float>(value);
|
|
285
|
+
|
|
286
|
+
if (RG_LIKELY(param.xmm_count)) {
|
|
287
|
+
memcpy(xmm_ptr++, &f, 4);
|
|
288
|
+
} else {
|
|
289
|
+
args_ptr = AlignUp(args_ptr, 4);
|
|
290
|
+
memcpy(args_ptr, &f, 4);
|
|
291
|
+
args_ptr += 4;
|
|
292
|
+
}
|
|
293
|
+
} break;
|
|
294
|
+
case PrimitiveKind::Float64: {
|
|
295
|
+
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
296
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
|
|
297
|
+
return env.Null();
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
double d = CopyNodeNumber<double>(value);
|
|
301
|
+
|
|
302
|
+
if (RG_LIKELY(param.xmm_count)) {
|
|
303
|
+
memcpy(xmm_ptr++, &d, 8);
|
|
304
|
+
} else {
|
|
305
|
+
args_ptr = AlignUp(args_ptr, 8);
|
|
306
|
+
memcpy(args_ptr, &d, 8);
|
|
307
|
+
args_ptr += 8;
|
|
308
|
+
}
|
|
309
|
+
} break;
|
|
310
|
+
case PrimitiveKind::String: {
|
|
311
|
+
if (RG_UNLIKELY(!value.IsString())) {
|
|
312
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected string", GetValueType(instance, value), i + 1);
|
|
313
|
+
return env.Null();
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
const char *str = CopyNodeString(value, &lib->tmp_alloc);
|
|
317
|
+
|
|
318
|
+
if (RG_LIKELY(param.gpr_count)) {
|
|
319
|
+
*(gpr_ptr++) = (uint64_t)str;
|
|
320
|
+
} else {
|
|
321
|
+
args_ptr = AlignUp(args_ptr, 8);
|
|
322
|
+
*(uint64_t *)args_ptr = (uint64_t)str;
|
|
323
|
+
args_ptr += 8;
|
|
324
|
+
}
|
|
325
|
+
} break;
|
|
326
|
+
case PrimitiveKind::Pointer: {
|
|
327
|
+
if (RG_UNLIKELY(!CheckValueTag(instance, value, param.type))) {
|
|
328
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected %3", GetValueType(instance, value), i + 1, param.type->name);
|
|
329
|
+
return env.Null();
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
void *ptr = value.As<Napi::External<void>>();
|
|
333
|
+
|
|
334
|
+
if (RG_LIKELY(param.gpr_count)) {
|
|
335
|
+
*(gpr_ptr++) = (uint64_t)ptr;
|
|
336
|
+
} else {
|
|
337
|
+
args_ptr = AlignUp(args_ptr, 8);
|
|
338
|
+
*(uint64_t *)args_ptr = (uint64_t)ptr;
|
|
339
|
+
args_ptr += 8;
|
|
340
|
+
}
|
|
341
|
+
} break;
|
|
342
|
+
|
|
343
|
+
case PrimitiveKind::Record: {
|
|
344
|
+
if (RG_UNLIKELY(!value.IsObject())) {
|
|
345
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected object", GetValueType(instance, value), i + 1);
|
|
346
|
+
return env.Null();
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
Napi::Object obj = value.As<Napi::Object>();
|
|
350
|
+
|
|
351
|
+
if (param.gpr_count || param.xmm_count) {
|
|
352
|
+
RG_ASSERT(param.type->size <= 16);
|
|
353
|
+
|
|
354
|
+
uint64_t buf[2] = {};
|
|
355
|
+
if (!PushObject(obj, param.type, &lib->tmp_alloc, (uint8_t *)buf))
|
|
356
|
+
return env.Null();
|
|
357
|
+
|
|
358
|
+
if (param.gpr_first) {
|
|
359
|
+
uint64_t *ptr = buf;
|
|
360
|
+
|
|
361
|
+
*(gpr_ptr++) = *(ptr++);
|
|
362
|
+
if (param.gpr_count == 2) {
|
|
363
|
+
*(gpr_ptr++) = *(ptr++);
|
|
364
|
+
} else if (param.xmm_count == 1) {
|
|
365
|
+
*(xmm_ptr++) = *(ptr++);
|
|
366
|
+
}
|
|
367
|
+
} else {
|
|
368
|
+
uint64_t *ptr = buf;
|
|
369
|
+
|
|
370
|
+
*(xmm_ptr++) = *(ptr++);
|
|
371
|
+
if (param.xmm_count == 2) {
|
|
372
|
+
*(xmm_ptr++) = *(ptr++);
|
|
373
|
+
} else if (param.gpr_count == 1) {
|
|
374
|
+
*(gpr_ptr++) = *(ptr++);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
} else if (param.use_memory) {
|
|
378
|
+
args_ptr = AlignUp(args_ptr, param.type->align);
|
|
379
|
+
if (!PushObject(obj, param.type, &lib->tmp_alloc, args_ptr))
|
|
380
|
+
return env.Null();
|
|
381
|
+
args_ptr += param.type->size;
|
|
382
|
+
}
|
|
383
|
+
} break;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// DumpStack(func, MakeSpan(sp_ptr, top_ptr - sp_ptr));
|
|
388
|
+
|
|
389
|
+
#define PERFORM_CALL(Suffix) \
|
|
390
|
+
(func->forward_fp ? ForwardCallX ## Suffix(func->func, sp_ptr) \
|
|
391
|
+
: ForwardCall ## Suffix(func->func, sp_ptr))
|
|
392
|
+
|
|
393
|
+
// Execute and convert return value
|
|
394
|
+
switch (func->ret.type->primitive) {
|
|
395
|
+
case PrimitiveKind::Float32: {
|
|
396
|
+
float f = PERFORM_CALL(F);
|
|
397
|
+
|
|
398
|
+
return Napi::Number::New(env, (double)f);
|
|
399
|
+
} break;
|
|
400
|
+
|
|
401
|
+
case PrimitiveKind::Float64: {
|
|
402
|
+
Xmm0RaxRet ret = PERFORM_CALL(DG);
|
|
403
|
+
|
|
404
|
+
return Napi::Number::New(env, ret.xmm0);
|
|
405
|
+
} break;
|
|
406
|
+
|
|
407
|
+
case PrimitiveKind::Record: {
|
|
408
|
+
if (func->ret.gpr_first && !func->ret.xmm_count) {
|
|
409
|
+
RaxRdxRet ret = PERFORM_CALL(GG);
|
|
410
|
+
|
|
411
|
+
Napi::Object obj = PopObject(env, (const uint8_t *)&ret, func->ret.type);
|
|
412
|
+
return obj;
|
|
413
|
+
} else if (func->ret.gpr_first) {
|
|
414
|
+
RaxXmm0Ret ret = PERFORM_CALL(GD);
|
|
415
|
+
|
|
416
|
+
Napi::Object obj = PopObject(env, (const uint8_t *)&ret, func->ret.type);
|
|
417
|
+
return obj;
|
|
418
|
+
} else if (func->ret.xmm_count) {
|
|
419
|
+
Xmm0RaxRet ret = PERFORM_CALL(DG);
|
|
420
|
+
|
|
421
|
+
Napi::Object obj = PopObject(env, (const uint8_t *)&ret, func->ret.type);
|
|
422
|
+
return obj;
|
|
423
|
+
} else if (func->ret.type->size) {
|
|
424
|
+
RG_ASSERT(return_ptr);
|
|
425
|
+
|
|
426
|
+
RaxRdxRet ret = PERFORM_CALL(GG);
|
|
427
|
+
RG_ASSERT(ret.rax == (uint64_t)return_ptr);
|
|
428
|
+
|
|
429
|
+
Napi::Object obj = PopObject(env, return_ptr, func->ret.type);
|
|
430
|
+
return obj;
|
|
431
|
+
} else {
|
|
432
|
+
PERFORM_CALL(GG);
|
|
433
|
+
|
|
434
|
+
Napi::Object obj = Napi::Object::New(env);
|
|
435
|
+
return obj;
|
|
436
|
+
}
|
|
437
|
+
} break;
|
|
438
|
+
|
|
439
|
+
default: {
|
|
440
|
+
RaxRdxRet ret = PERFORM_CALL(GG);
|
|
441
|
+
|
|
442
|
+
switch (func->ret.type->primitive) {
|
|
443
|
+
case PrimitiveKind::Void: return env.Null();
|
|
444
|
+
case PrimitiveKind::Bool: return Napi::Boolean::New(env, ret.rax);
|
|
445
|
+
case PrimitiveKind::Int8: return Napi::Number::New(env, (double)ret.rax);
|
|
446
|
+
case PrimitiveKind::UInt8: return Napi::Number::New(env, (double)ret.rax);
|
|
447
|
+
case PrimitiveKind::Int16: return Napi::Number::New(env, (double)ret.rax);
|
|
448
|
+
case PrimitiveKind::UInt16: return Napi::Number::New(env, (double)ret.rax);
|
|
449
|
+
case PrimitiveKind::Int32: return Napi::Number::New(env, (double)ret.rax);
|
|
450
|
+
case PrimitiveKind::UInt32: return Napi::Number::New(env, (double)ret.rax);
|
|
451
|
+
case PrimitiveKind::Int64: return Napi::BigInt::New(env, (int64_t)ret.rax);
|
|
452
|
+
case PrimitiveKind::UInt64: return Napi::BigInt::New(env, ret.rax);
|
|
453
|
+
case PrimitiveKind::Float32: { RG_UNREACHABLE(); } break;
|
|
454
|
+
case PrimitiveKind::Float64: { RG_UNREACHABLE(); } break;
|
|
455
|
+
case PrimitiveKind::String: return Napi::String::New(env, (const char *)ret.rax);
|
|
456
|
+
case PrimitiveKind::Pointer: {
|
|
457
|
+
void *ptr = (void *)ret.rax;
|
|
458
|
+
|
|
459
|
+
Napi::External<void> external = Napi::External<void>::New(env, ptr);
|
|
460
|
+
SetValueTag(instance, external, func->ret.type);
|
|
461
|
+
|
|
462
|
+
return external;
|
|
463
|
+
} break;
|
|
464
|
+
|
|
465
|
+
case PrimitiveKind::Record: { RG_UNREACHABLE(); } break;
|
|
466
|
+
}
|
|
467
|
+
} break;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
#undef PERFORM_CALL
|
|
471
|
+
|
|
472
|
+
RG_UNREACHABLE();
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
#endif
|
|
@@ -0,0 +1,131 @@
|
|
|
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 five are the same, but they differ (in the C side) by their return type.
|
|
15
|
+
// Unlike the five next functions, these ones don't forward XMM 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 XMM 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 RAX, in order to save it through argument forwarding.
|
|
30
|
+
// Save RSP in RBX (non-volatile), and use carefully assembled stack provided by caller.
|
|
31
|
+
.macro prologue
|
|
32
|
+
.cfi_startproc
|
|
33
|
+
.cfi_def_cfa rsp, 8
|
|
34
|
+
endbr64
|
|
35
|
+
movq %rdi, %rax
|
|
36
|
+
pushq %rbx
|
|
37
|
+
.cfi_def_cfa rsp, 16
|
|
38
|
+
movq %rsp, %rbx
|
|
39
|
+
.cfi_def_cfa rbx, 16
|
|
40
|
+
movq %rsi, %rsp
|
|
41
|
+
addq $112, %rsp
|
|
42
|
+
.endm
|
|
43
|
+
|
|
44
|
+
// Call native function.
|
|
45
|
+
// Once done, restore normal stack pointer and return.
|
|
46
|
+
// The return value is passed untouched through RAX or XMM0.
|
|
47
|
+
.macro epilogue
|
|
48
|
+
call *%rax
|
|
49
|
+
movq %rbx, %rsp
|
|
50
|
+
popq %rbx
|
|
51
|
+
.cfi_def_cfa rsp, 8
|
|
52
|
+
ret
|
|
53
|
+
.cfi_endproc
|
|
54
|
+
.endm
|
|
55
|
+
|
|
56
|
+
// Prepare integer argument registers from array passed by caller.
|
|
57
|
+
.macro forward_int
|
|
58
|
+
movq 40(%rsi), %r9
|
|
59
|
+
movq 32(%rsi), %r8
|
|
60
|
+
movq 24(%rsi), %rcx
|
|
61
|
+
movq 16(%rsi), %rdx
|
|
62
|
+
movq 0(%rsi), %rdi
|
|
63
|
+
movq 8(%rsi), %rsi
|
|
64
|
+
.endm
|
|
65
|
+
|
|
66
|
+
// Prepare XMM argument registers from array passed by caller.
|
|
67
|
+
.macro forward_xmm
|
|
68
|
+
movsd 104(%rsi), %xmm7
|
|
69
|
+
movsd 96(%rsi), %xmm6
|
|
70
|
+
movsd 88(%rsi), %xmm5
|
|
71
|
+
movsd 80(%rsi), %xmm4
|
|
72
|
+
movsd 72(%rsi), %xmm3
|
|
73
|
+
movsd 64(%rsi), %xmm2
|
|
74
|
+
movsd 56(%rsi), %xmm1
|
|
75
|
+
movsd 48(%rsi), %xmm0
|
|
76
|
+
.endm
|
|
77
|
+
|
|
78
|
+
ForwardCallGG:
|
|
79
|
+
prologue
|
|
80
|
+
forward_int
|
|
81
|
+
epilogue
|
|
82
|
+
|
|
83
|
+
ForwardCallF:
|
|
84
|
+
prologue
|
|
85
|
+
forward_int
|
|
86
|
+
epilogue
|
|
87
|
+
|
|
88
|
+
ForwardCallDG:
|
|
89
|
+
prologue
|
|
90
|
+
forward_int
|
|
91
|
+
epilogue
|
|
92
|
+
|
|
93
|
+
ForwardCallGD:
|
|
94
|
+
prologue
|
|
95
|
+
forward_int
|
|
96
|
+
epilogue
|
|
97
|
+
|
|
98
|
+
ForwardCallDD:
|
|
99
|
+
prologue
|
|
100
|
+
forward_int
|
|
101
|
+
epilogue
|
|
102
|
+
|
|
103
|
+
ForwardCallXGG:
|
|
104
|
+
prologue
|
|
105
|
+
forward_xmm
|
|
106
|
+
forward_int
|
|
107
|
+
epilogue
|
|
108
|
+
|
|
109
|
+
ForwardCallXF:
|
|
110
|
+
prologue
|
|
111
|
+
forward_xmm
|
|
112
|
+
forward_int
|
|
113
|
+
epilogue
|
|
114
|
+
|
|
115
|
+
ForwardCallXDG:
|
|
116
|
+
prologue
|
|
117
|
+
forward_xmm
|
|
118
|
+
forward_int
|
|
119
|
+
epilogue
|
|
120
|
+
|
|
121
|
+
ForwardCallXGD:
|
|
122
|
+
prologue
|
|
123
|
+
forward_xmm
|
|
124
|
+
forward_int
|
|
125
|
+
epilogue
|
|
126
|
+
|
|
127
|
+
ForwardCallXDD:
|
|
128
|
+
prologue
|
|
129
|
+
forward_xmm
|
|
130
|
+
forward_int
|
|
131
|
+
epilogue
|