koffi 1.1.1 → 1.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CMakeLists.txt +13 -7
- package/README.md +15 -26
- package/build/qemu/1.1.4/koffi_darwin_x64.tar.gz +0 -0
- package/build/qemu/1.1.4/koffi_freebsd_arm64.tar.gz +0 -0
- package/build/qemu/1.1.4/koffi_freebsd_ia32.tar.gz +0 -0
- package/build/qemu/1.1.4/koffi_freebsd_x64.tar.gz +0 -0
- package/build/qemu/1.1.4/koffi_linux_arm.tar.gz +0 -0
- package/build/qemu/1.1.4/koffi_linux_arm64.tar.gz +0 -0
- package/build/qemu/1.1.4/koffi_linux_ia32.tar.gz +0 -0
- package/build/qemu/1.1.4/koffi_linux_riscv64.tar.gz +0 -0
- package/build/qemu/1.1.4/koffi_linux_x64.tar.gz +0 -0
- package/build/qemu/1.1.4/koffi_openbsd_ia32.tar.gz +0 -0
- package/build/qemu/1.1.4/koffi_openbsd_x64.tar.gz +0 -0
- package/build/qemu/1.1.4/koffi_win32_ia32.tar.gz +0 -0
- package/build/qemu/1.1.4/koffi_win32_x64.tar.gz +0 -0
- package/package.json +2 -2
- package/qemu/qemu.js +13 -10
- package/qemu/registry/machines.json +138 -3
- package/qemu/registry/sha256sum.txt +27 -12
- package/src/abi_arm32.cc +29 -16
- package/src/abi_arm64.cc +33 -17
- package/src/abi_riscv64.cc +468 -0
- package/src/abi_riscv64_fwd.S +129 -0
- package/src/abi_x64_sysv.cc +9 -10
- package/src/abi_x64_win.cc +5 -8
- package/src/abi_x86.cc +11 -6
- package/src/call.cc +24 -36
- package/src/call.hh +14 -24
- package/src/ffi.cc +75 -27
- package/src/ffi.hh +13 -5
- package/src/parser.cc +48 -26
- package/src/parser.hh +3 -1
- package/src/util.cc +26 -57
- package/src/util.hh +17 -1
- package/test/CMakeLists.txt +3 -0
- package/test/misc.c +34 -0
- package/vendor/_patches/glfw_001_fix_openbsd_xlib_soname.patch +145 -0
- package/vendor/libcc/libcc.cc +7 -7
- package/vendor/libcc/libcc.hh +8 -2
- package/vendor/raylib/src/external/glfw/src/egl_context.c +6 -0
- package/vendor/raylib/src/external/glfw/src/osmesa_context.c +2 -0
- package/vendor/raylib/src/external/glfw/src/vulkan.c +2 -0
- package/vendor/raylib/src/external/glfw/src/x11_init.c +20 -0
- package/build/qemu/1.1.1/koffi_darwin_x64.tar.gz +0 -0
- package/build/qemu/1.1.1/koffi_freebsd_arm64.tar.gz +0 -0
- package/build/qemu/1.1.1/koffi_freebsd_ia32.tar.gz +0 -0
- package/build/qemu/1.1.1/koffi_freebsd_x64.tar.gz +0 -0
- package/build/qemu/1.1.1/koffi_linux_arm.tar.gz +0 -0
- package/build/qemu/1.1.1/koffi_linux_arm64.tar.gz +0 -0
- package/build/qemu/1.1.1/koffi_linux_ia32.tar.gz +0 -0
- package/build/qemu/1.1.1/koffi_linux_x64.tar.gz +0 -0
- package/build/qemu/1.1.1/koffi_win32_ia32.tar.gz +0 -0
- package/build/qemu/1.1.1/koffi_win32_x64.tar.gz +0 -0
package/src/abi_x86.cc
CHANGED
|
@@ -37,7 +37,9 @@ static inline bool IsRegular(Size size)
|
|
|
37
37
|
|
|
38
38
|
bool AnalyseFunction(InstanceData *instance, FunctionInfo *func)
|
|
39
39
|
{
|
|
40
|
-
int fast = (func->convention == CallConvention::Fastcall) ? 2 :
|
|
40
|
+
int fast = (func->convention == CallConvention::Fastcall) ? 2 :
|
|
41
|
+
(func->convention == CallConvention::Thiscall) ? 1 : 0;
|
|
42
|
+
func->fast = fast;
|
|
41
43
|
|
|
42
44
|
if (func->ret.type->primitive != PrimitiveKind::Record) {
|
|
43
45
|
func->ret.trivial = true;
|
|
@@ -77,6 +79,10 @@ bool AnalyseFunction(InstanceData *instance, FunctionInfo *func)
|
|
|
77
79
|
func->decorated_name = Fmt(&instance->str_alloc, "@%1@%2", func->name, params_size).ptr;
|
|
78
80
|
func->args_size += 16;
|
|
79
81
|
} break;
|
|
82
|
+
case CallConvention::Thiscall: {
|
|
83
|
+
RG_ASSERT(!func->variadic);
|
|
84
|
+
func->args_size += 16;
|
|
85
|
+
} break;
|
|
80
86
|
}
|
|
81
87
|
|
|
82
88
|
return true;
|
|
@@ -90,7 +96,7 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
90
96
|
// Pass return value in register or through memory
|
|
91
97
|
if (RG_UNLIKELY(!AllocStack(func->args_size, 16, &args_ptr)))
|
|
92
98
|
return false;
|
|
93
|
-
if (func->
|
|
99
|
+
if (func->fast) {
|
|
94
100
|
fast_ptr = args_ptr;
|
|
95
101
|
args_ptr += 4;
|
|
96
102
|
}
|
|
@@ -249,8 +255,7 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
249
255
|
}
|
|
250
256
|
}
|
|
251
257
|
|
|
252
|
-
|
|
253
|
-
heap = MakeSpan(old_heap_mem.ptr, mem->heap.ptr - old_heap_mem.ptr);
|
|
258
|
+
sp = mem->stack.end();
|
|
254
259
|
|
|
255
260
|
return true;
|
|
256
261
|
}
|
|
@@ -259,8 +264,8 @@ void CallData::Execute()
|
|
|
259
264
|
{
|
|
260
265
|
#define PERFORM_CALL(Suffix) \
|
|
261
266
|
([&]() { \
|
|
262
|
-
auto ret = (func->
|
|
263
|
-
|
|
267
|
+
auto ret = (func->fast ? ForwardCallR ## Suffix(func->func, sp) \
|
|
268
|
+
: ForwardCall ## Suffix(func->func, sp)); \
|
|
264
269
|
return ret; \
|
|
265
270
|
})()
|
|
266
271
|
|
package/src/call.cc
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
namespace RG {
|
|
22
22
|
|
|
23
23
|
CallData::CallData(Napi::Env env, InstanceData *instance, const FunctionInfo *func, InstanceMemory *mem)
|
|
24
|
-
: env(env), instance(instance), func(func),
|
|
24
|
+
: env(env), instance(instance), func(func),
|
|
25
25
|
mem(mem), old_stack_mem(mem->stack), old_heap_mem(mem->heap)
|
|
26
26
|
{
|
|
27
27
|
mem->depth++;
|
|
@@ -252,8 +252,8 @@ bool CallData::PushObject(const Napi::Object &obj, const TypeInfo *type, uint8_t
|
|
|
252
252
|
return false;
|
|
253
253
|
}
|
|
254
254
|
|
|
255
|
-
Napi::Object
|
|
256
|
-
if (!PushObject(
|
|
255
|
+
Napi::Object obj2 = value.As<Napi::Object>();
|
|
256
|
+
if (!PushObject(obj2, member.type, dest, realign))
|
|
257
257
|
return false;
|
|
258
258
|
} break;
|
|
259
259
|
case PrimitiveKind::Array: {
|
|
@@ -292,15 +292,15 @@ bool CallData::PushObject(const Napi::Object &obj, const TypeInfo *type, uint8_t
|
|
|
292
292
|
return true;
|
|
293
293
|
}
|
|
294
294
|
|
|
295
|
-
bool CallData::PushArray(const Napi::Value &
|
|
295
|
+
bool CallData::PushArray(const Napi::Value &obj, const TypeInfo *type, uint8_t *dest, int16_t realign)
|
|
296
296
|
{
|
|
297
|
-
RG_ASSERT(
|
|
297
|
+
RG_ASSERT(obj.IsArray() || obj.IsTypedArray() || obj.IsString());
|
|
298
298
|
RG_ASSERT(type->primitive == PrimitiveKind::Array);
|
|
299
299
|
|
|
300
300
|
uint32_t len = type->size / type->ref->size;
|
|
301
301
|
|
|
302
|
-
if (
|
|
303
|
-
Napi::Array array =
|
|
302
|
+
if (obj.IsArray()) {
|
|
303
|
+
Napi::Array array = obj.As<Napi::Array>();
|
|
304
304
|
|
|
305
305
|
if (RG_UNLIKELY(array.Length() != len)) {
|
|
306
306
|
ThrowError<Napi::Error>(env, "Expected array of length %1, got %2", len, array.Length());
|
|
@@ -407,15 +407,15 @@ bool CallData::PushArray(const Napi::Value &value, const TypeInfo *type, uint8_t
|
|
|
407
407
|
} break;
|
|
408
408
|
case PrimitiveKind::Record: {
|
|
409
409
|
PUSH_ARRAY(IsObject(value), "object", {
|
|
410
|
-
Napi::Object
|
|
411
|
-
if (!PushObject(
|
|
410
|
+
Napi::Object obj2 = value.As<Napi::Object>();
|
|
411
|
+
if (!PushObject(obj2, type->ref, dest, realign))
|
|
412
412
|
return false;
|
|
413
413
|
});
|
|
414
414
|
} break;
|
|
415
415
|
case PrimitiveKind::Array: {
|
|
416
416
|
PUSH_ARRAY(value.IsArray() || value.IsTypedArray() || value.IsString(), "array", {
|
|
417
|
-
Napi::Object
|
|
418
|
-
if (!PushArray(
|
|
417
|
+
Napi::Object array2 = value.As<Napi::Array>();
|
|
418
|
+
if (!PushArray(array2, type->ref, dest, realign))
|
|
419
419
|
return false;
|
|
420
420
|
});
|
|
421
421
|
} break;
|
|
@@ -434,8 +434,8 @@ bool CallData::PushArray(const Napi::Value &value, const TypeInfo *type, uint8_t
|
|
|
434
434
|
}
|
|
435
435
|
|
|
436
436
|
#undef PUSH_ARRAY
|
|
437
|
-
} else if (
|
|
438
|
-
Napi::TypedArray array =
|
|
437
|
+
} else if (obj.IsTypedArray()) {
|
|
438
|
+
Napi::TypedArray array = obj.As<Napi::TypedArray>();
|
|
439
439
|
const uint8_t *buf = (const uint8_t *)array.ArrayBuffer().Data();
|
|
440
440
|
|
|
441
441
|
if (RG_UNLIKELY(array.ElementLength() != len)) {
|
|
@@ -469,23 +469,23 @@ bool CallData::PushArray(const Napi::Value &value, const TypeInfo *type, uint8_t
|
|
|
469
469
|
|
|
470
470
|
dest += type->ref->size;
|
|
471
471
|
}
|
|
472
|
-
} else if (
|
|
473
|
-
size_t
|
|
472
|
+
} else if (obj.IsString()) {
|
|
473
|
+
size_t encoded = 0;
|
|
474
474
|
|
|
475
475
|
if (type->ref->primitive == PrimitiveKind::Int8 || type->ref->primitive == PrimitiveKind::UInt8) {
|
|
476
|
-
napi_status status = napi_get_value_string_utf8(env,
|
|
476
|
+
napi_status status = napi_get_value_string_utf8(env, obj, (char *)dest, type->size, &encoded);
|
|
477
477
|
RG_ASSERT(status == napi_ok);
|
|
478
478
|
} else if (type->ref->primitive == PrimitiveKind::Int16 || type->ref->primitive == PrimitiveKind::UInt16) {
|
|
479
|
-
napi_status status = napi_get_value_string_utf16(env,
|
|
479
|
+
napi_status status = napi_get_value_string_utf16(env, obj, (char16_t *)dest, type->size / 2, &encoded);
|
|
480
480
|
RG_ASSERT(status == napi_ok);
|
|
481
481
|
|
|
482
|
-
|
|
482
|
+
encoded *= 2;
|
|
483
483
|
} else {
|
|
484
484
|
ThrowError<Napi::TypeError>(env, "Strings cannot be converted to %1 array", type->ref->name);
|
|
485
485
|
return false;
|
|
486
486
|
}
|
|
487
487
|
|
|
488
|
-
memset_safe(dest +
|
|
488
|
+
memset_safe(dest + encoded, 0, type->size - encoded);
|
|
489
489
|
} else {
|
|
490
490
|
RG_UNREACHABLE();
|
|
491
491
|
}
|
|
@@ -565,13 +565,11 @@ void CallData::PopObject(Napi::Object obj, const uint8_t *src, const TypeInfo *t
|
|
|
565
565
|
obj.Set(member.name, value);
|
|
566
566
|
} break;
|
|
567
567
|
case PrimitiveKind::Float32: {
|
|
568
|
-
float f;
|
|
569
|
-
memcpy(&f, src, 4);
|
|
568
|
+
float f = *(float *)src;
|
|
570
569
|
obj.Set(member.name, Napi::Number::New(env, (double)f));
|
|
571
570
|
} break;
|
|
572
571
|
case PrimitiveKind::Float64: {
|
|
573
|
-
double d;
|
|
574
|
-
memcpy(&d, src, 8);
|
|
572
|
+
double d = *(double *)src;
|
|
575
573
|
obj.Set(member.name, Napi::Number::New(env, d));
|
|
576
574
|
} break;
|
|
577
575
|
}
|
|
@@ -762,19 +760,6 @@ Napi::Value CallData::PopArray(const uint8_t *src, const TypeInfo *type, int16_t
|
|
|
762
760
|
RG_UNREACHABLE();
|
|
763
761
|
}
|
|
764
762
|
|
|
765
|
-
Napi::Value CallData::Run(const Napi::CallbackInfo &info)
|
|
766
|
-
{
|
|
767
|
-
if (!RG_UNLIKELY(Prepare(info)))
|
|
768
|
-
return env.Null();
|
|
769
|
-
|
|
770
|
-
if (debug) {
|
|
771
|
-
DumpDebug();
|
|
772
|
-
}
|
|
773
|
-
Execute();
|
|
774
|
-
|
|
775
|
-
return Complete();
|
|
776
|
-
}
|
|
777
|
-
|
|
778
763
|
static void DumpMemory(const char *type, Span<const uint8_t> bytes)
|
|
779
764
|
{
|
|
780
765
|
if (bytes.len) {
|
|
@@ -805,6 +790,9 @@ void CallData::DumpDebug() const
|
|
|
805
790
|
}
|
|
806
791
|
PrintLn(stderr, "Return: %1 (%2)", func->ret.type->name, FmtMemSize(func->ret.type->size));
|
|
807
792
|
|
|
793
|
+
Span<const uint8_t> stack = MakeSpan(mem->stack.end(), old_stack_mem.end() - mem->stack.end());
|
|
794
|
+
Span<const uint8_t> heap = MakeSpan(old_heap_mem.ptr, mem->heap.ptr - old_heap_mem.ptr);
|
|
795
|
+
|
|
808
796
|
DumpMemory("Stack", stack);
|
|
809
797
|
DumpMemory("Heap", heap);
|
|
810
798
|
}
|
package/src/call.hh
CHANGED
|
@@ -34,16 +34,12 @@ class CallData {
|
|
|
34
34
|
InstanceData *instance;
|
|
35
35
|
const FunctionInfo *func;
|
|
36
36
|
|
|
37
|
-
bool debug;
|
|
38
|
-
|
|
39
37
|
InstanceMemory *mem;
|
|
40
38
|
Span<uint8_t> old_stack_mem;
|
|
41
39
|
Span<uint8_t> old_heap_mem;
|
|
42
40
|
|
|
43
41
|
LocalArray<OutObject, MaxOutParameters> out_objects;
|
|
44
|
-
|
|
45
|
-
Span<uint8_t> heap;
|
|
46
|
-
Span<uint8_t> stack;
|
|
42
|
+
uint8_t *sp;
|
|
47
43
|
|
|
48
44
|
union {
|
|
49
45
|
uint32_t u32;
|
|
@@ -65,20 +61,18 @@ public:
|
|
|
65
61
|
void Execute();
|
|
66
62
|
Napi::Value Complete();
|
|
67
63
|
|
|
68
|
-
Napi::Value Run(const Napi::CallbackInfo &info);
|
|
69
|
-
|
|
70
64
|
void DumpDebug() const;
|
|
71
65
|
|
|
72
66
|
private:
|
|
73
67
|
template <typename T = void>
|
|
74
|
-
bool AllocStack(Size size, Size align, T **out_ptr
|
|
68
|
+
bool AllocStack(Size size, Size align, T **out_ptr);
|
|
75
69
|
template <typename T = void>
|
|
76
|
-
bool AllocHeap(Size size, Size align, T **out_ptr
|
|
70
|
+
bool AllocHeap(Size size, Size align, T **out_ptr);
|
|
77
71
|
|
|
78
72
|
const char *PushString(const Napi::Value &value);
|
|
79
73
|
const char16_t *PushString16(const Napi::Value &value);
|
|
80
74
|
bool PushObject(const Napi::Object &obj, const TypeInfo *type, uint8_t *dest, int16_t realign = 0);
|
|
81
|
-
bool PushArray(const Napi::Value &
|
|
75
|
+
bool PushArray(const Napi::Value &obj, const TypeInfo *type, uint8_t *dest, int16_t realign = 0);
|
|
82
76
|
|
|
83
77
|
void PopObject(Napi::Object obj, const uint8_t *src, const TypeInfo *type, int16_t realign = 0);
|
|
84
78
|
Napi::Object PopObject(const uint8_t *src, const TypeInfo *type, int16_t realign = 0);
|
|
@@ -86,7 +80,7 @@ private:
|
|
|
86
80
|
};
|
|
87
81
|
|
|
88
82
|
template <typename T>
|
|
89
|
-
bool CallData::AllocStack(Size size, Size align, T **out_ptr)
|
|
83
|
+
inline bool CallData::AllocStack(Size size, Size align, T **out_ptr)
|
|
90
84
|
{
|
|
91
85
|
uint8_t *ptr = AlignDown(mem->stack.end() - size, align);
|
|
92
86
|
Size delta = mem->stack.end() - ptr;
|
|
@@ -96,20 +90,18 @@ bool CallData::AllocStack(Size size, Size align, T **out_ptr)
|
|
|
96
90
|
return false;
|
|
97
91
|
}
|
|
98
92
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
93
|
+
#ifdef RG_DEBUG
|
|
94
|
+
memset(ptr, 0, delta);
|
|
95
|
+
#endif
|
|
102
96
|
|
|
103
97
|
mem->stack.len -= delta;
|
|
104
98
|
|
|
105
|
-
|
|
106
|
-
*out_ptr = (T *)ptr;
|
|
107
|
-
}
|
|
99
|
+
*out_ptr = (T *)ptr;
|
|
108
100
|
return true;
|
|
109
101
|
}
|
|
110
102
|
|
|
111
103
|
template <typename T>
|
|
112
|
-
bool CallData::AllocHeap(Size size, Size align, T **out_ptr)
|
|
104
|
+
inline bool CallData::AllocHeap(Size size, Size align, T **out_ptr)
|
|
113
105
|
{
|
|
114
106
|
uint8_t *ptr = AlignUp(mem->heap.ptr, align);
|
|
115
107
|
Size delta = size + (ptr - mem->heap.ptr);
|
|
@@ -119,16 +111,14 @@ bool CallData::AllocHeap(Size size, Size align, T **out_ptr)
|
|
|
119
111
|
return false;
|
|
120
112
|
}
|
|
121
113
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
114
|
+
#ifdef RG_DEBUG
|
|
115
|
+
memset(mem->heap.ptr, 0, (size_t)delta);
|
|
116
|
+
#endif
|
|
125
117
|
|
|
126
118
|
mem->heap.ptr += delta;
|
|
127
119
|
mem->heap.len -= delta;
|
|
128
120
|
|
|
129
|
-
|
|
130
|
-
*out_ptr = (T *)ptr;
|
|
131
|
-
}
|
|
121
|
+
*out_ptr = (T *)ptr;
|
|
132
122
|
return true;
|
|
133
123
|
}
|
|
134
124
|
|
package/src/ffi.cc
CHANGED
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
#else
|
|
30
30
|
#include <dlfcn.h>
|
|
31
31
|
#include <unistd.h>
|
|
32
|
+
#include <sys/mman.h>
|
|
32
33
|
#endif
|
|
33
34
|
|
|
34
35
|
#include <napi.h>
|
|
@@ -39,6 +40,11 @@
|
|
|
39
40
|
|
|
40
41
|
namespace RG {
|
|
41
42
|
|
|
43
|
+
const Size SyncStackSize = Mebibytes(2);
|
|
44
|
+
const Size SyncHeapSize = Mebibytes(4);
|
|
45
|
+
const Size AsyncStackSize = Mebibytes(1);
|
|
46
|
+
const Size AsyncHeapSize = Mebibytes(2);
|
|
47
|
+
|
|
42
48
|
// Value does not matter, the tag system uses memory addresses
|
|
43
49
|
const int TypeInfoMarker = 0xDEADBEEF;
|
|
44
50
|
|
|
@@ -100,6 +106,11 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
|
|
|
100
106
|
type->members.Append(member);
|
|
101
107
|
}
|
|
102
108
|
|
|
109
|
+
if (!type->size) {
|
|
110
|
+
ThrowError<Napi::TypeError>(env, "Empty struct '%1' is not allowed in C", type->name);
|
|
111
|
+
return env.Null();
|
|
112
|
+
}
|
|
113
|
+
|
|
103
114
|
type->size = (int16_t)AlignLen(type->size, type->align);
|
|
104
115
|
|
|
105
116
|
// If the insert succeeds, we cannot fail anymore
|
|
@@ -290,7 +301,7 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
|
|
|
290
301
|
if (!ref)
|
|
291
302
|
return env.Null();
|
|
292
303
|
if (len <= 0) {
|
|
293
|
-
ThrowError<Napi::TypeError>(env, "Array length must be non-zero
|
|
304
|
+
ThrowError<Napi::TypeError>(env, "Array length must be positive and non-zero");
|
|
294
305
|
return env.Null();
|
|
295
306
|
}
|
|
296
307
|
if (len > INT16_MAX / ref->size) {
|
|
@@ -369,21 +380,6 @@ static Napi::Value GetTypeDefinition(const Napi::CallbackInfo &info)
|
|
|
369
380
|
return type->defn.Value();
|
|
370
381
|
}
|
|
371
382
|
|
|
372
|
-
static Span<uint8_t> AllocateAndAlign16(Allocator *alloc, Size size)
|
|
373
|
-
{
|
|
374
|
-
RG_ASSERT(AlignLen(size, 16) == size);
|
|
375
|
-
RG_ASSERT(size >= Kibibytes(1));
|
|
376
|
-
|
|
377
|
-
// Account for allocator overhead
|
|
378
|
-
size -= 256;
|
|
379
|
-
|
|
380
|
-
uint8_t *ptr = (uint8_t *)Allocator::Allocate(alloc, size);
|
|
381
|
-
uint8_t *aligned = AlignUp(ptr, 16);
|
|
382
|
-
Size delta = AlignLen(aligned - ptr, 16);
|
|
383
|
-
|
|
384
|
-
return MakeSpan(aligned, size - delta);
|
|
385
|
-
}
|
|
386
|
-
|
|
387
383
|
static InstanceMemory *AllocateAsyncMemory(InstanceData *instance)
|
|
388
384
|
{
|
|
389
385
|
for (Size i = 1; i < instance->memories.len; i++) {
|
|
@@ -395,8 +391,23 @@ static InstanceMemory *AllocateAsyncMemory(InstanceData *instance)
|
|
|
395
391
|
|
|
396
392
|
InstanceMemory *mem = new InstanceMemory();
|
|
397
393
|
|
|
398
|
-
mem->stack =
|
|
399
|
-
|
|
394
|
+
mem->stack.len = AsyncStackSize;
|
|
395
|
+
#if defined(_WIN32)
|
|
396
|
+
mem->stack.ptr = (uint8_t *)VirtualAlloc(nullptr, mem->stack.len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
|
397
|
+
#elif defined(__APPLE__)
|
|
398
|
+
mem->stack.ptr = (uint8_t *)mmap(nullptr, mem->stack.len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
|
399
|
+
#else
|
|
400
|
+
mem->stack.ptr = (uint8_t *)mmap(nullptr, mem->stack.len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_STACK, -1, 0);
|
|
401
|
+
#endif
|
|
402
|
+
RG_CRITICAL(mem->stack.ptr, "Failed to allocate %1 of memory", mem->stack.len);
|
|
403
|
+
|
|
404
|
+
mem->heap.len = AsyncHeapSize;
|
|
405
|
+
#ifdef _WIN32
|
|
406
|
+
mem->heap.ptr = (uint8_t *)VirtualAlloc(nullptr, mem->heap.len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
|
407
|
+
#else
|
|
408
|
+
mem->heap.ptr = (uint8_t *)mmap(nullptr, mem->heap.len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
|
409
|
+
#endif
|
|
410
|
+
RG_CRITICAL(mem->heap.ptr, "Failed to allocate %1 of memory", mem->heap.len);
|
|
400
411
|
|
|
401
412
|
if (instance->memories.Available()) {
|
|
402
413
|
instance->memories.Append(mem);
|
|
@@ -421,7 +432,15 @@ static Napi::Value TranslateNormalCall(const Napi::CallbackInfo &info)
|
|
|
421
432
|
InstanceMemory *mem = instance->memories[0];
|
|
422
433
|
CallData call(env, instance, func, mem);
|
|
423
434
|
|
|
424
|
-
|
|
435
|
+
if (!RG_UNLIKELY(call.Prepare(info)))
|
|
436
|
+
return env.Null();
|
|
437
|
+
|
|
438
|
+
if (instance->debug) {
|
|
439
|
+
call.DumpDebug();
|
|
440
|
+
}
|
|
441
|
+
call.Execute();
|
|
442
|
+
|
|
443
|
+
return call.Complete();
|
|
425
444
|
}
|
|
426
445
|
|
|
427
446
|
static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
|
|
@@ -481,7 +500,15 @@ static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
|
|
|
481
500
|
InstanceMemory *mem = instance->memories[0];
|
|
482
501
|
CallData call(env, instance, &func, mem);
|
|
483
502
|
|
|
484
|
-
|
|
503
|
+
if (!RG_UNLIKELY(call.Prepare(info)))
|
|
504
|
+
return env.Null();
|
|
505
|
+
|
|
506
|
+
if (instance->debug) {
|
|
507
|
+
call.DumpDebug();
|
|
508
|
+
}
|
|
509
|
+
call.Execute();
|
|
510
|
+
|
|
511
|
+
return call.Complete();
|
|
485
512
|
}
|
|
486
513
|
|
|
487
514
|
class AsyncCall: public Napi::AsyncWorker {
|
|
@@ -597,10 +624,10 @@ static bool ParseClassicFunction(Napi::Env env, Napi::String name, Napi::Value r
|
|
|
597
624
|
return false;
|
|
598
625
|
}
|
|
599
626
|
|
|
600
|
-
|
|
627
|
+
uint32_t parameters_len = parameters.Length();
|
|
601
628
|
|
|
602
629
|
if (parameters_len) {
|
|
603
|
-
Napi::String str = ((Napi::Value)parameters[
|
|
630
|
+
Napi::String str = ((Napi::Value)parameters[parameters_len - 1]).As<Napi::String>();
|
|
604
631
|
|
|
605
632
|
if (str.IsString() && str.Utf8Value() == "...") {
|
|
606
633
|
func->variadic = true;
|
|
@@ -653,9 +680,13 @@ static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info, CallConve
|
|
|
653
680
|
if (!ParseClassicFunction(env, info[0u].As<Napi::String>(), info[1u], info[2u].As<Napi::Array>(), func))
|
|
654
681
|
return env.Null();
|
|
655
682
|
} else if (info.Length() >= 1) {
|
|
656
|
-
|
|
683
|
+
if (!info[0].IsString()) {
|
|
684
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for prototype, expected string", GetValueType(instance, info[0]));
|
|
685
|
+
return env.Null();
|
|
686
|
+
}
|
|
657
687
|
|
|
658
|
-
|
|
688
|
+
std::string proto = info[0u].As<Napi::String>();
|
|
689
|
+
if (!ParsePrototype(env, proto.c_str(), func))
|
|
659
690
|
return env.Null();
|
|
660
691
|
} else {
|
|
661
692
|
ThrowError<Napi::TypeError>(env, "Expected 1 or 3 arguments, not %1", info.Length());
|
|
@@ -784,6 +815,7 @@ static Napi::Value LoadSharedLibrary(const Napi::CallbackInfo &info)
|
|
|
784
815
|
ADD_CONVENTION("cdecl", CallConvention::Cdecl);
|
|
785
816
|
ADD_CONVENTION("stdcall", CallConvention::Stdcall);
|
|
786
817
|
ADD_CONVENTION("fastcall", CallConvention::Fastcall);
|
|
818
|
+
ADD_CONVENTION("thiscall", CallConvention::Thiscall);
|
|
787
819
|
|
|
788
820
|
#undef ADD_CONVENTION
|
|
789
821
|
|
|
@@ -928,8 +960,23 @@ InstanceData::InstanceData()
|
|
|
928
960
|
{
|
|
929
961
|
InstanceMemory *mem = new InstanceMemory();
|
|
930
962
|
|
|
931
|
-
mem->stack =
|
|
932
|
-
|
|
963
|
+
mem->stack.len = SyncStackSize;
|
|
964
|
+
#if defined(_WIN32)
|
|
965
|
+
mem->stack.ptr = (uint8_t *)VirtualAlloc(nullptr, mem->stack.len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
|
966
|
+
#elif defined(__APPLE__)
|
|
967
|
+
mem->stack.ptr = (uint8_t *)mmap(nullptr, mem->stack.len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
|
968
|
+
#else
|
|
969
|
+
mem->stack.ptr = (uint8_t *)mmap(nullptr, mem->stack.len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_STACK, -1, 0);
|
|
970
|
+
#endif
|
|
971
|
+
RG_CRITICAL(mem->stack.ptr, "Failed to allocate %1 of memory", mem->stack.len);
|
|
972
|
+
|
|
973
|
+
mem->heap.len = SyncHeapSize;
|
|
974
|
+
#ifdef _WIN32
|
|
975
|
+
mem->heap.ptr = (uint8_t *)VirtualAlloc(nullptr, mem->heap.len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
|
976
|
+
#else
|
|
977
|
+
mem->heap.ptr = (uint8_t *)mmap(nullptr, mem->heap.len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
|
978
|
+
#endif
|
|
979
|
+
RG_CRITICAL(mem->heap.ptr, "Failed to allocate %1 of memory", mem->heap.len);
|
|
933
980
|
|
|
934
981
|
memories.Append(mem);
|
|
935
982
|
}
|
|
@@ -957,7 +1004,6 @@ static void SetExports(Napi::Env env, Func func)
|
|
|
957
1004
|
func("out", Napi::Function::New(env, MarkOut));
|
|
958
1005
|
func("inout", Napi::Function::New(env, MarkInOut));
|
|
959
1006
|
|
|
960
|
-
func("internal", Napi::Boolean::New(env, true));
|
|
961
1007
|
#if defined(_WIN32)
|
|
962
1008
|
func("extension", Napi::String::New(env, ".dll"));
|
|
963
1009
|
#elif defined(__APPLE__)
|
|
@@ -1009,6 +1055,7 @@ static void InitInternal(v8::Local<v8::Object> target, v8::Local<v8::Value>,
|
|
|
1009
1055
|
FillRandomSafe(&instance->tag_lower, RG_SIZE(instance->tag_lower));
|
|
1010
1056
|
|
|
1011
1057
|
SetExports(env_napi, [&](const char *name, Napi::Value value) { SetValue(env, target, name, value); });
|
|
1058
|
+
SetValue(env, target, "internal", Napi::Boolean::New(env_cxx, true));
|
|
1012
1059
|
}
|
|
1013
1060
|
|
|
1014
1061
|
#else
|
|
@@ -1024,6 +1071,7 @@ static Napi::Object InitModule(Napi::Env env, Napi::Object exports)
|
|
|
1024
1071
|
FillRandomSafe(&instance->tag_lower, RG_SIZE(instance->tag_lower));
|
|
1025
1072
|
|
|
1026
1073
|
SetExports(env, [&](const char *name, Napi::Value value) { exports.Set(name, value); });
|
|
1074
|
+
exports.Set("internal", Napi::Boolean::New(env, false));
|
|
1027
1075
|
|
|
1028
1076
|
return exports;
|
|
1029
1077
|
}
|
package/src/ffi.hh
CHANGED
|
@@ -109,12 +109,14 @@ struct LibraryHolder {
|
|
|
109
109
|
enum class CallConvention {
|
|
110
110
|
Cdecl,
|
|
111
111
|
Stdcall,
|
|
112
|
-
Fastcall
|
|
112
|
+
Fastcall,
|
|
113
|
+
Thiscall
|
|
113
114
|
};
|
|
114
115
|
static const char *const CallConventionNames[] = {
|
|
115
116
|
"Cdecl",
|
|
116
117
|
"Stdcall",
|
|
117
|
-
"Fastcall"
|
|
118
|
+
"Fastcall",
|
|
119
|
+
"Thiscall"
|
|
118
120
|
};
|
|
119
121
|
|
|
120
122
|
struct ParameterInfo {
|
|
@@ -139,6 +141,11 @@ struct ParameterInfo {
|
|
|
139
141
|
#elif defined(__i386__) || defined(_M_IX86)
|
|
140
142
|
bool trivial; // Only matters for return value
|
|
141
143
|
bool fast;
|
|
144
|
+
#elif __riscv_xlen == 64
|
|
145
|
+
bool use_memory;
|
|
146
|
+
int8_t gpr_count;
|
|
147
|
+
int8_t vec_count;
|
|
148
|
+
bool gpr_first; // Only for structs
|
|
142
149
|
#endif
|
|
143
150
|
};
|
|
144
151
|
|
|
@@ -160,9 +167,12 @@ struct FunctionInfo {
|
|
|
160
167
|
// ABI-specific part
|
|
161
168
|
|
|
162
169
|
Size args_size;
|
|
163
|
-
#if defined(__arm__) || defined(__aarch64__) || defined(__x86_64__) || defined(_WIN64)
|
|
170
|
+
#if defined(__arm__) || defined(__aarch64__) || defined(__x86_64__) || defined(_WIN64) || defined(__riscv)
|
|
164
171
|
bool forward_fp;
|
|
165
172
|
#endif
|
|
173
|
+
#if defined(__i386__) || defined(_M_IX86)
|
|
174
|
+
bool fast;
|
|
175
|
+
#endif
|
|
166
176
|
|
|
167
177
|
~FunctionInfo();
|
|
168
178
|
|
|
@@ -171,8 +181,6 @@ struct FunctionInfo {
|
|
|
171
181
|
};
|
|
172
182
|
|
|
173
183
|
struct InstanceMemory {
|
|
174
|
-
LinkedAllocator mem_alloc;
|
|
175
|
-
|
|
176
184
|
Span<uint8_t> stack;
|
|
177
185
|
Span<uint8_t> heap;
|
|
178
186
|
|