koffi 1.1.5 → 1.2.0-alpha.3
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/README.md +47 -3
- package/package.json +2 -3
- package/qemu/registry/machines.json +26 -13
- package/src/abi_arm32.cc +520 -34
- package/src/abi_arm32_fwd.S +237 -22
- package/src/abi_arm64.cc +558 -23
- package/src/abi_arm64_fwd.S +236 -38
- package/src/abi_arm64_fwd.asm +232 -16
- package/src/abi_riscv64.cc +438 -66
- package/src/abi_riscv64_fwd.S +216 -23
- package/src/abi_x64_sysv.cc +449 -77
- package/src/abi_x64_sysv_fwd.S +175 -86
- package/src/abi_x64_win.cc +407 -18
- package/src/abi_x64_win_fwd.asm +215 -0
- package/src/abi_x86.cc +412 -21
- package/src/abi_x86_fwd.S +223 -18
- package/src/abi_x86_fwd.asm +218 -0
- package/src/call.cc +113 -17
- package/src/call.hh +17 -3
- package/src/ffi.cc +142 -103
- package/src/ffi.hh +24 -5
- package/src/parser.cc +1 -1
- package/test/misc.c +74 -0
package/src/call.hh
CHANGED
|
@@ -23,7 +23,11 @@ namespace RG {
|
|
|
23
23
|
|
|
24
24
|
bool AnalyseFunction(InstanceData *instance, FunctionInfo *func);
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
struct BackRegisters;
|
|
27
|
+
|
|
28
|
+
// I'm not sure why the alignas(8), because alignof(CallData) is 8 without it.
|
|
29
|
+
// But on Windows i386, without it, the alignment may not be correct (compiler bug?).
|
|
30
|
+
class alignas(8) CallData {
|
|
27
31
|
struct OutObject {
|
|
28
32
|
Napi::ObjectReference ref;
|
|
29
33
|
const uint8_t *ptr;
|
|
@@ -37,9 +41,12 @@ class CallData {
|
|
|
37
41
|
InstanceMemory *mem;
|
|
38
42
|
Span<uint8_t> old_stack_mem;
|
|
39
43
|
Span<uint8_t> old_heap_mem;
|
|
44
|
+
uint32_t used_trampolines = 0;
|
|
40
45
|
|
|
41
46
|
LocalArray<OutObject, MaxOutParameters> out_objects;
|
|
42
|
-
|
|
47
|
+
|
|
48
|
+
uint8_t *new_sp;
|
|
49
|
+
uint8_t *old_sp;
|
|
43
50
|
|
|
44
51
|
union {
|
|
45
52
|
uint32_t u32;
|
|
@@ -61,6 +68,8 @@ public:
|
|
|
61
68
|
void Execute();
|
|
62
69
|
Napi::Value Complete();
|
|
63
70
|
|
|
71
|
+
void Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg);
|
|
72
|
+
|
|
64
73
|
void DumpDebug() const;
|
|
65
74
|
|
|
66
75
|
private:
|
|
@@ -77,6 +86,8 @@ private:
|
|
|
77
86
|
void PopObject(Napi::Object obj, const uint8_t *src, const TypeInfo *type, int16_t realign = 0);
|
|
78
87
|
Napi::Object PopObject(const uint8_t *src, const TypeInfo *type, int16_t realign = 0);
|
|
79
88
|
Napi::Value PopArray(const uint8_t *src, const TypeInfo *type, int16_t realign = 0);
|
|
89
|
+
|
|
90
|
+
Size ReserveTrampoline(const FunctionInfo *proto, Napi::Function func);
|
|
80
91
|
};
|
|
81
92
|
|
|
82
93
|
template <typename T>
|
|
@@ -85,7 +96,8 @@ inline bool CallData::AllocStack(Size size, Size align, T **out_ptr)
|
|
|
85
96
|
uint8_t *ptr = AlignDown(mem->stack.end() - size, align);
|
|
86
97
|
Size delta = mem->stack.end() - ptr;
|
|
87
98
|
|
|
88
|
-
|
|
99
|
+
// Keep 512 bytes for redzone (required in some ABIs)
|
|
100
|
+
if (RG_UNLIKELY(mem->stack.len - 512 < delta)) {
|
|
89
101
|
ThrowError<Napi::Error>(env, "FFI call is taking up too much memory");
|
|
90
102
|
return false;
|
|
91
103
|
}
|
|
@@ -122,4 +134,6 @@ inline bool CallData::AllocHeap(Size size, Size align, T **out_ptr)
|
|
|
122
134
|
return true;
|
|
123
135
|
}
|
|
124
136
|
|
|
137
|
+
void *GetTrampoline(Size idx, const FunctionInfo *proto);
|
|
138
|
+
|
|
125
139
|
}
|
package/src/ffi.cc
CHANGED
|
@@ -40,11 +40,6 @@
|
|
|
40
40
|
|
|
41
41
|
namespace RG {
|
|
42
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
|
-
|
|
48
43
|
// Value does not matter, the tag system uses memory addresses
|
|
49
44
|
const int TypeInfoMarker = 0xDEADBEEF;
|
|
50
45
|
|
|
@@ -325,6 +320,140 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
|
|
|
325
320
|
return external;
|
|
326
321
|
}
|
|
327
322
|
|
|
323
|
+
static bool ParseClassicFunction(Napi::Env env, Napi::String name, Napi::Value ret,
|
|
324
|
+
Napi::Array parameters, FunctionInfo *func)
|
|
325
|
+
{
|
|
326
|
+
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
327
|
+
|
|
328
|
+
#ifdef _WIN32
|
|
329
|
+
if (!name.IsString() && !name.IsNumber()) {
|
|
330
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string or integer", GetValueType(instance, name));
|
|
331
|
+
return false;
|
|
332
|
+
}
|
|
333
|
+
#else
|
|
334
|
+
if (!name.IsString()) {
|
|
335
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, name));
|
|
336
|
+
return false;
|
|
337
|
+
}
|
|
338
|
+
#endif
|
|
339
|
+
|
|
340
|
+
func->name = DuplicateString(name.ToString().Utf8Value().c_str(), &instance->str_alloc).ptr;
|
|
341
|
+
|
|
342
|
+
func->ret.type = ResolveType(instance, ret);
|
|
343
|
+
if (!func->ret.type)
|
|
344
|
+
return false;
|
|
345
|
+
if (func->ret.type->primitive == PrimitiveKind::Array) {
|
|
346
|
+
ThrowError<Napi::Error>(env, "You are not allowed to directly return fixed-size arrays");
|
|
347
|
+
return false;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (!parameters.IsArray()) {
|
|
351
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for parameters of '%2', expected an array", GetValueType(instance, parameters), func->name);
|
|
352
|
+
return false;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
uint32_t parameters_len = parameters.Length();
|
|
356
|
+
|
|
357
|
+
if (parameters_len) {
|
|
358
|
+
Napi::String str = ((Napi::Value)parameters[parameters_len - 1]).As<Napi::String>();
|
|
359
|
+
|
|
360
|
+
if (str.IsString() && str.Utf8Value() == "...") {
|
|
361
|
+
func->variadic = true;
|
|
362
|
+
parameters_len--;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
for (uint32_t j = 0; j < parameters_len; j++) {
|
|
367
|
+
ParameterInfo param = {};
|
|
368
|
+
|
|
369
|
+
param.type = ResolveType(instance, parameters[j], ¶m.directions);
|
|
370
|
+
if (!param.type)
|
|
371
|
+
return false;
|
|
372
|
+
if (param.type->primitive == PrimitiveKind::Void ||
|
|
373
|
+
param.type->primitive == PrimitiveKind::Array) {
|
|
374
|
+
ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter", param.type->name);
|
|
375
|
+
return false;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
if (func->parameters.len >= MaxParameters) {
|
|
379
|
+
ThrowError<Napi::TypeError>(env, "Functions cannot have more than %1 parameters", MaxParameters);
|
|
380
|
+
return false;
|
|
381
|
+
}
|
|
382
|
+
if ((param.directions & 2) && ++func->out_parameters >= MaxOutParameters) {
|
|
383
|
+
ThrowError<Napi::TypeError>(env, "Functions cannot have more than out %1 parameters", MaxOutParameters);
|
|
384
|
+
return false;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
param.offset = (int8_t)j;
|
|
388
|
+
|
|
389
|
+
func->parameters.Append(param);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
return true;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
static Napi::Value CreateCallbackType(const Napi::CallbackInfo &info)
|
|
396
|
+
{
|
|
397
|
+
Napi::Env env = info.Env();
|
|
398
|
+
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
399
|
+
|
|
400
|
+
FunctionInfo *func = instance->callbacks.AppendDefault();
|
|
401
|
+
RG_DEFER_N(err_guard) { instance->callbacks.RemoveLast(1); };
|
|
402
|
+
|
|
403
|
+
if (info.Length() >= 3) {
|
|
404
|
+
if (!ParseClassicFunction(env, info[0u].As<Napi::String>(), info[1u], info[2u].As<Napi::Array>(), func))
|
|
405
|
+
return env.Null();
|
|
406
|
+
} else if (info.Length() >= 1) {
|
|
407
|
+
if (!info[0].IsString()) {
|
|
408
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for prototype, expected string", GetValueType(instance, info[0]));
|
|
409
|
+
return env.Null();
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
std::string proto = info[0u].As<Napi::String>();
|
|
413
|
+
if (!ParsePrototype(env, proto.c_str(), func))
|
|
414
|
+
return env.Null();
|
|
415
|
+
} else {
|
|
416
|
+
ThrowError<Napi::TypeError>(env, "Expected 1 or 3 arguments, not %1", info.Length());
|
|
417
|
+
return env.Null();
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
if (func->variadic) {
|
|
421
|
+
LogError("Variadic callbacks are not supported");
|
|
422
|
+
return env.Null();
|
|
423
|
+
}
|
|
424
|
+
if (func->convention != CallConvention::Cdecl &&
|
|
425
|
+
func->convention != CallConvention::Stdcall) {
|
|
426
|
+
ThrowError<Napi::Error>(env, "Only Cdecl and Stdcall callbacks are supported");
|
|
427
|
+
return env.Null();
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
if (!AnalyseFunction(instance, func))
|
|
431
|
+
return env.Null();
|
|
432
|
+
|
|
433
|
+
// We cannot fail after this check
|
|
434
|
+
if (instance->types_map.Find(func->name)) {
|
|
435
|
+
ThrowError<Napi::Error>(env, "Duplicate type name '%1'", func->name);
|
|
436
|
+
return env.Null();
|
|
437
|
+
}
|
|
438
|
+
err_guard.Disable();
|
|
439
|
+
|
|
440
|
+
TypeInfo *type = instance->types.AppendDefault();
|
|
441
|
+
|
|
442
|
+
type->name = func->name;
|
|
443
|
+
|
|
444
|
+
type->primitive = PrimitiveKind::Callback;
|
|
445
|
+
type->align = alignof(void *);
|
|
446
|
+
type->size = RG_SIZE(void *);
|
|
447
|
+
type->proto = func;
|
|
448
|
+
|
|
449
|
+
instance->types_map.Set(type);
|
|
450
|
+
|
|
451
|
+
Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, type);
|
|
452
|
+
SetValueTag(instance, external, &TypeInfoMarker);
|
|
453
|
+
|
|
454
|
+
return external;
|
|
455
|
+
}
|
|
456
|
+
|
|
328
457
|
static Napi::Value GetTypeSize(const Napi::CallbackInfo &info)
|
|
329
458
|
{
|
|
330
459
|
Napi::Env env = info.Env();
|
|
@@ -380,7 +509,7 @@ static Napi::Value GetTypeDefinition(const Napi::CallbackInfo &info)
|
|
|
380
509
|
return type->defn.Value();
|
|
381
510
|
}
|
|
382
511
|
|
|
383
|
-
static InstanceMemory *
|
|
512
|
+
static InstanceMemory *AllocateMemory(InstanceData *instance)
|
|
384
513
|
{
|
|
385
514
|
for (Size i = 1; i < instance->memories.len; i++) {
|
|
386
515
|
InstanceMemory *mem = instance->memories[i];
|
|
@@ -391,7 +520,7 @@ static InstanceMemory *AllocateAsyncMemory(InstanceData *instance)
|
|
|
391
520
|
|
|
392
521
|
InstanceMemory *mem = new InstanceMemory();
|
|
393
522
|
|
|
394
|
-
mem->stack.len =
|
|
523
|
+
mem->stack.len = StackSize;
|
|
395
524
|
#if defined(_WIN32)
|
|
396
525
|
mem->stack.ptr = (uint8_t *)VirtualAlloc(nullptr, mem->stack.len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
|
397
526
|
#elif defined(__APPLE__)
|
|
@@ -401,7 +530,7 @@ static InstanceMemory *AllocateAsyncMemory(InstanceData *instance)
|
|
|
401
530
|
#endif
|
|
402
531
|
RG_CRITICAL(mem->stack.ptr, "Failed to allocate %1 of memory", mem->stack.len);
|
|
403
532
|
|
|
404
|
-
mem->heap.len =
|
|
533
|
+
mem->heap.len = HeapSize;
|
|
405
534
|
#ifdef _WIN32
|
|
406
535
|
mem->heap.ptr = (uint8_t *)VirtualAlloc(nullptr, mem->heap.len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
|
407
536
|
#else
|
|
@@ -489,7 +618,7 @@ static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
|
|
|
489
618
|
}
|
|
490
619
|
|
|
491
620
|
param.variadic = true;
|
|
492
|
-
param.offset = i + 1;
|
|
621
|
+
param.offset = (int8_t)(i + 1);
|
|
493
622
|
|
|
494
623
|
func.parameters.Append(param);
|
|
495
624
|
}
|
|
@@ -581,7 +710,7 @@ static Napi::Value TranslateAsyncCall(const Napi::CallbackInfo &info)
|
|
|
581
710
|
return env.Null();
|
|
582
711
|
}
|
|
583
712
|
|
|
584
|
-
InstanceMemory *mem =
|
|
713
|
+
InstanceMemory *mem = AllocateMemory(instance);
|
|
585
714
|
AsyncCall *async = new AsyncCall(env, instance, func, mem, callback);
|
|
586
715
|
|
|
587
716
|
if (async->Prepare(info) && instance->debug) {
|
|
@@ -592,78 +721,6 @@ static Napi::Value TranslateAsyncCall(const Napi::CallbackInfo &info)
|
|
|
592
721
|
return env.Null();
|
|
593
722
|
}
|
|
594
723
|
|
|
595
|
-
static bool ParseClassicFunction(Napi::Env env, Napi::String name, Napi::Value ret,
|
|
596
|
-
Napi::Array parameters, FunctionInfo *func)
|
|
597
|
-
{
|
|
598
|
-
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
599
|
-
|
|
600
|
-
#ifdef _WIN32
|
|
601
|
-
if (!name.IsString() && !name.IsNumber()) {
|
|
602
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string or integer", GetValueType(instance, name));
|
|
603
|
-
return false;
|
|
604
|
-
}
|
|
605
|
-
#else
|
|
606
|
-
if (!name.IsString()) {
|
|
607
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, name));
|
|
608
|
-
return false;
|
|
609
|
-
}
|
|
610
|
-
#endif
|
|
611
|
-
|
|
612
|
-
func->name = DuplicateString(name.ToString().Utf8Value().c_str(), &instance->str_alloc).ptr;
|
|
613
|
-
|
|
614
|
-
func->ret.type = ResolveType(instance, ret);
|
|
615
|
-
if (!func->ret.type)
|
|
616
|
-
return false;
|
|
617
|
-
if (func->ret.type->primitive == PrimitiveKind::Array) {
|
|
618
|
-
ThrowError<Napi::Error>(env, "You are not allowed to directly return fixed-size arrays");
|
|
619
|
-
return false;
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
if (!parameters.IsArray()) {
|
|
623
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for parameters of '%2', expected an array", GetValueType(instance, parameters), func->name);
|
|
624
|
-
return false;
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
uint32_t parameters_len = parameters.Length();
|
|
628
|
-
|
|
629
|
-
if (parameters_len) {
|
|
630
|
-
Napi::String str = ((Napi::Value)parameters[parameters_len - 1]).As<Napi::String>();
|
|
631
|
-
|
|
632
|
-
if (str.IsString() && str.Utf8Value() == "...") {
|
|
633
|
-
func->variadic = true;
|
|
634
|
-
parameters_len--;
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
for (uint32_t j = 0; j < parameters_len; j++) {
|
|
639
|
-
ParameterInfo param = {};
|
|
640
|
-
|
|
641
|
-
param.type = ResolveType(instance, parameters[j], ¶m.directions);
|
|
642
|
-
if (!param.type)
|
|
643
|
-
return false;
|
|
644
|
-
if (param.type->primitive == PrimitiveKind::Void ||
|
|
645
|
-
param.type->primitive == PrimitiveKind::Array) {
|
|
646
|
-
ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter", param.type->name);
|
|
647
|
-
return false;
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
if (func->parameters.len >= MaxParameters) {
|
|
651
|
-
ThrowError<Napi::TypeError>(env, "Functions cannot have more than %1 parameters", MaxParameters);
|
|
652
|
-
return false;
|
|
653
|
-
}
|
|
654
|
-
if ((param.directions & 2) && ++func->out_parameters >= MaxOutParameters) {
|
|
655
|
-
ThrowError<Napi::TypeError>(env, "Functions cannot have more than out %1 parameters", MaxOutParameters);
|
|
656
|
-
return false;
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
param.offset = j;
|
|
660
|
-
|
|
661
|
-
func->parameters.Append(param);
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
return true;
|
|
665
|
-
}
|
|
666
|
-
|
|
667
724
|
static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info, CallConvention convention)
|
|
668
725
|
{
|
|
669
726
|
Napi::Env env = info.Env();
|
|
@@ -977,27 +1034,8 @@ InstanceMemory::~InstanceMemory()
|
|
|
977
1034
|
|
|
978
1035
|
InstanceData::InstanceData()
|
|
979
1036
|
{
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
mem->stack.len = SyncStackSize;
|
|
983
|
-
#if defined(_WIN32)
|
|
984
|
-
mem->stack.ptr = (uint8_t *)VirtualAlloc(nullptr, mem->stack.len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
|
985
|
-
#elif defined(__APPLE__)
|
|
986
|
-
mem->stack.ptr = (uint8_t *)mmap(nullptr, mem->stack.len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
|
987
|
-
#else
|
|
988
|
-
mem->stack.ptr = (uint8_t *)mmap(nullptr, mem->stack.len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_STACK, -1, 0);
|
|
989
|
-
#endif
|
|
990
|
-
RG_CRITICAL(mem->stack.ptr, "Failed to allocate %1 of memory", mem->stack.len);
|
|
991
|
-
|
|
992
|
-
mem->heap.len = SyncHeapSize;
|
|
993
|
-
#ifdef _WIN32
|
|
994
|
-
mem->heap.ptr = (uint8_t *)VirtualAlloc(nullptr, mem->heap.len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
|
995
|
-
#else
|
|
996
|
-
mem->heap.ptr = (uint8_t *)mmap(nullptr, mem->heap.len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
|
997
|
-
#endif
|
|
998
|
-
RG_CRITICAL(mem->heap.ptr, "Failed to allocate %1 of memory", mem->heap.len);
|
|
999
|
-
|
|
1000
|
-
memories.Append(mem);
|
|
1037
|
+
AllocateMemory(this);
|
|
1038
|
+
RG_ASSERT(memories.len == 1);
|
|
1001
1039
|
}
|
|
1002
1040
|
|
|
1003
1041
|
InstanceData::~InstanceData()
|
|
@@ -1015,6 +1053,7 @@ static void SetExports(Napi::Env env, Func func)
|
|
|
1015
1053
|
func("handle", Napi::Function::New(env, CreateHandleType));
|
|
1016
1054
|
func("pointer", Napi::Function::New(env, CreatePointerType));
|
|
1017
1055
|
func("array", Napi::Function::New(env, CreateArrayType));
|
|
1056
|
+
func("callback", Napi::Function::New(env, CreateCallbackType));
|
|
1018
1057
|
func("sizeof", Napi::Function::New(env, GetTypeSize));
|
|
1019
1058
|
func("alignof", Napi::Function::New(env, GetTypeAlign));
|
|
1020
1059
|
func("introspect", Napi::Function::New(env, GetTypeDefinition));
|
package/src/ffi.hh
CHANGED
|
@@ -19,8 +19,12 @@
|
|
|
19
19
|
|
|
20
20
|
namespace RG {
|
|
21
21
|
|
|
22
|
+
static const Size StackSize = Mebibytes(1);
|
|
23
|
+
static const Size HeapSize = Mebibytes(2);
|
|
24
|
+
|
|
22
25
|
static const Size MaxParameters = 32;
|
|
23
26
|
static const Size MaxOutParameters = 8;
|
|
27
|
+
static const Size MaxTrampolines = 16;
|
|
24
28
|
|
|
25
29
|
extern const int TypeInfoMarker;
|
|
26
30
|
|
|
@@ -41,7 +45,8 @@ enum class PrimitiveKind {
|
|
|
41
45
|
Record,
|
|
42
46
|
Array,
|
|
43
47
|
Float32,
|
|
44
|
-
Float64
|
|
48
|
+
Float64,
|
|
49
|
+
Callback
|
|
45
50
|
};
|
|
46
51
|
static const char *const PrimitiveKindNames[] = {
|
|
47
52
|
"Void",
|
|
@@ -60,11 +65,13 @@ static const char *const PrimitiveKindNames[] = {
|
|
|
60
65
|
"Record",
|
|
61
66
|
"Array",
|
|
62
67
|
"Float32",
|
|
63
|
-
"Float64"
|
|
68
|
+
"Float64",
|
|
69
|
+
"Callback"
|
|
64
70
|
};
|
|
65
71
|
|
|
66
72
|
struct TypeInfo;
|
|
67
73
|
struct RecordMember;
|
|
74
|
+
struct FunctionInfo;
|
|
68
75
|
|
|
69
76
|
struct TypeInfo {
|
|
70
77
|
enum class ArrayHint {
|
|
@@ -85,6 +92,7 @@ struct TypeInfo {
|
|
|
85
92
|
HeapArray<RecordMember> members; // Record only
|
|
86
93
|
const TypeInfo *ref; // Pointer or array
|
|
87
94
|
ArrayHint hint; // Array only
|
|
95
|
+
const FunctionInfo *proto; // Callback only
|
|
88
96
|
|
|
89
97
|
RG_HASHTABLE_HANDLER(TypeInfo, name);
|
|
90
98
|
};
|
|
@@ -123,7 +131,7 @@ struct ParameterInfo {
|
|
|
123
131
|
const TypeInfo *type;
|
|
124
132
|
int directions;
|
|
125
133
|
bool variadic;
|
|
126
|
-
|
|
134
|
+
int8_t offset;
|
|
127
135
|
|
|
128
136
|
// ABI-specific part
|
|
129
137
|
|
|
@@ -149,11 +157,12 @@ struct ParameterInfo {
|
|
|
149
157
|
#endif
|
|
150
158
|
};
|
|
151
159
|
|
|
160
|
+
// Also used for callbacks, even though many members are not used in this case
|
|
152
161
|
struct FunctionInfo {
|
|
153
162
|
mutable std::atomic_int refcount {1};
|
|
154
163
|
|
|
155
164
|
const char *name;
|
|
156
|
-
const char *decorated_name;
|
|
165
|
+
const char *decorated_name; // Only set for some platforms/calling conventions
|
|
157
166
|
const LibraryHolder *lib = nullptr;
|
|
158
167
|
|
|
159
168
|
void *func;
|
|
@@ -161,7 +170,7 @@ struct FunctionInfo {
|
|
|
161
170
|
|
|
162
171
|
ParameterInfo ret;
|
|
163
172
|
HeapArray<ParameterInfo> parameters;
|
|
164
|
-
|
|
173
|
+
int8_t out_parameters;
|
|
165
174
|
bool variadic;
|
|
166
175
|
|
|
167
176
|
// ABI-specific part
|
|
@@ -190,19 +199,29 @@ struct InstanceMemory {
|
|
|
190
199
|
bool temporary;
|
|
191
200
|
};
|
|
192
201
|
|
|
202
|
+
struct TrampolineInfo {
|
|
203
|
+
const FunctionInfo *proto;
|
|
204
|
+
Napi::Function func;
|
|
205
|
+
};
|
|
206
|
+
|
|
193
207
|
struct InstanceData {
|
|
194
208
|
InstanceData();
|
|
195
209
|
~InstanceData();
|
|
196
210
|
|
|
197
211
|
BucketArray<TypeInfo> types;
|
|
198
212
|
HashTable<const char *, TypeInfo *> types_map;
|
|
213
|
+
BucketArray<FunctionInfo> callbacks;
|
|
199
214
|
|
|
200
215
|
bool debug;
|
|
201
216
|
uint64_t tag_lower;
|
|
202
217
|
|
|
203
218
|
LocalArray<InstanceMemory *, 6> memories;
|
|
204
219
|
|
|
220
|
+
TrampolineInfo trampolines[MaxTrampolines];
|
|
221
|
+
uint32_t free_trampolines = UINT32_MAX;
|
|
222
|
+
|
|
205
223
|
BlockAllocator str_alloc;
|
|
206
224
|
};
|
|
225
|
+
RG_STATIC_ASSERT(MaxTrampolines <= 32);
|
|
207
226
|
|
|
208
227
|
}
|
package/src/parser.cc
CHANGED
package/test/misc.c
CHANGED
|
@@ -120,6 +120,10 @@ typedef struct FixedWide {
|
|
|
120
120
|
int16_t buf[64];
|
|
121
121
|
} FixedWide;
|
|
122
122
|
|
|
123
|
+
typedef struct SingleU32 { uint32_t v; } SingleU32;
|
|
124
|
+
typedef struct SingleU64 { uint64_t v; } SingleU64;
|
|
125
|
+
typedef struct SingleI64 { int64_t v; } SingleI64;
|
|
126
|
+
|
|
123
127
|
EXPORT void FillPack1(int a, Pack1 *p)
|
|
124
128
|
{
|
|
125
129
|
p->a = a;
|
|
@@ -410,3 +414,73 @@ EXPORT FixedWide ReturnFixedWide(FixedWide str)
|
|
|
410
414
|
{
|
|
411
415
|
return str;
|
|
412
416
|
}
|
|
417
|
+
|
|
418
|
+
EXPORT uint32_t ThroughUInt32UU(uint32_t v)
|
|
419
|
+
{
|
|
420
|
+
return v;
|
|
421
|
+
}
|
|
422
|
+
EXPORT SingleU32 ThroughUInt32SS(SingleU32 s)
|
|
423
|
+
{
|
|
424
|
+
return s;
|
|
425
|
+
}
|
|
426
|
+
EXPORT SingleU32 ThroughUInt32SU(uint32_t v)
|
|
427
|
+
{
|
|
428
|
+
SingleU32 s;
|
|
429
|
+
s.v = v;
|
|
430
|
+
return s;
|
|
431
|
+
}
|
|
432
|
+
EXPORT uint32_t ThroughUInt32US(SingleU32 s)
|
|
433
|
+
{
|
|
434
|
+
return s.v;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
EXPORT uint64_t ThroughUInt64UU(uint64_t v)
|
|
438
|
+
{
|
|
439
|
+
return v;
|
|
440
|
+
}
|
|
441
|
+
EXPORT SingleU64 ThroughUInt64SS(SingleU64 s)
|
|
442
|
+
{
|
|
443
|
+
return s;
|
|
444
|
+
}
|
|
445
|
+
EXPORT SingleU64 ThroughUInt64SU(uint64_t v)
|
|
446
|
+
{
|
|
447
|
+
SingleU64 s;
|
|
448
|
+
s.v = v;
|
|
449
|
+
return s;
|
|
450
|
+
}
|
|
451
|
+
EXPORT uint64_t ThroughUInt64US(SingleU64 s)
|
|
452
|
+
{
|
|
453
|
+
return s.v;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
EXPORT int64_t ThroughInt64II(int64_t v)
|
|
457
|
+
{
|
|
458
|
+
return v;
|
|
459
|
+
}
|
|
460
|
+
EXPORT SingleI64 ThroughInt64SS(SingleI64 s)
|
|
461
|
+
{
|
|
462
|
+
return s;
|
|
463
|
+
}
|
|
464
|
+
EXPORT SingleI64 ThroughInt64SI(int64_t v)
|
|
465
|
+
{
|
|
466
|
+
SingleI64 s;
|
|
467
|
+
s.v = v;
|
|
468
|
+
return s;
|
|
469
|
+
}
|
|
470
|
+
EXPORT int64_t ThroughInt64IS(SingleI64 s)
|
|
471
|
+
{
|
|
472
|
+
return s.v;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
EXPORT float CallSimpleJS(int i, float (*func)(int i, const char *str, double d))
|
|
476
|
+
{
|
|
477
|
+
float f = func(i, "Hello!", 42.0);
|
|
478
|
+
return f;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
EXPORT int TransferToJS(const char *str, int (*cb)(const char *str))
|
|
482
|
+
{
|
|
483
|
+
char buf[64];
|
|
484
|
+
snprintf(buf, sizeof(buf), "Hello %s!", str);
|
|
485
|
+
return cb(buf);
|
|
486
|
+
}
|