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/abi_arm64.cc
CHANGED
|
@@ -33,13 +33,65 @@ struct HfaRet {
|
|
|
33
33
|
double d3;
|
|
34
34
|
};
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
struct BackRegisters {
|
|
37
|
+
uint64_t x0;
|
|
38
|
+
uint64_t x1;
|
|
39
|
+
double d0;
|
|
40
|
+
double d1;
|
|
41
|
+
double d2;
|
|
42
|
+
double d3;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
extern "C" X0X1Ret ForwardCallGG(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
46
|
+
extern "C" float ForwardCallF(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
47
|
+
extern "C" HfaRet ForwardCallDDDD(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
39
48
|
|
|
40
|
-
extern "C" X0X1Ret ForwardCallXGG(const void *func, uint8_t *sp);
|
|
41
|
-
extern "C" float ForwardCallXF(const void *func, uint8_t *sp);
|
|
42
|
-
extern "C" HfaRet ForwardCallXDDDD(const void *func, uint8_t *sp);
|
|
49
|
+
extern "C" X0X1Ret ForwardCallXGG(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
50
|
+
extern "C" float ForwardCallXF(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
51
|
+
extern "C" HfaRet ForwardCallXDDDD(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
52
|
+
|
|
53
|
+
extern "C" int Trampoline0; extern "C" int TrampolineX0;
|
|
54
|
+
extern "C" int Trampoline1; extern "C" int TrampolineX1;
|
|
55
|
+
extern "C" int Trampoline2; extern "C" int TrampolineX2;
|
|
56
|
+
extern "C" int Trampoline3; extern "C" int TrampolineX3;
|
|
57
|
+
extern "C" int Trampoline4; extern "C" int TrampolineX4;
|
|
58
|
+
extern "C" int Trampoline5; extern "C" int TrampolineX5;
|
|
59
|
+
extern "C" int Trampoline6; extern "C" int TrampolineX6;
|
|
60
|
+
extern "C" int Trampoline7; extern "C" int TrampolineX7;
|
|
61
|
+
extern "C" int Trampoline8; extern "C" int TrampolineX8;
|
|
62
|
+
extern "C" int Trampoline9; extern "C" int TrampolineX9;
|
|
63
|
+
extern "C" int Trampoline10; extern "C" int TrampolineX10;
|
|
64
|
+
extern "C" int Trampoline11; extern "C" int TrampolineX11;
|
|
65
|
+
extern "C" int Trampoline12; extern "C" int TrampolineX12;
|
|
66
|
+
extern "C" int Trampoline13; extern "C" int TrampolineX13;
|
|
67
|
+
extern "C" int Trampoline14; extern "C" int TrampolineX14;
|
|
68
|
+
extern "C" int Trampoline15; extern "C" int TrampolineX15;
|
|
69
|
+
|
|
70
|
+
extern "C" napi_value CallSwitchStack(Napi::Function *func, size_t argc, napi_value *argv,
|
|
71
|
+
uint8_t *old_sp, Span<uint8_t> *new_stack,
|
|
72
|
+
napi_value (*call)(Napi::Function *func, size_t argc, napi_value *argv));
|
|
73
|
+
|
|
74
|
+
static void *const Trampolines[][2] = {
|
|
75
|
+
{ &Trampoline0, &TrampolineX0 },
|
|
76
|
+
{ &Trampoline1, &TrampolineX1 },
|
|
77
|
+
{ &Trampoline2, &TrampolineX2 },
|
|
78
|
+
{ &Trampoline3, &TrampolineX3 },
|
|
79
|
+
{ &Trampoline4, &TrampolineX4 },
|
|
80
|
+
{ &Trampoline5, &TrampolineX5 },
|
|
81
|
+
{ &Trampoline6, &TrampolineX6 },
|
|
82
|
+
{ &Trampoline7, &TrampolineX7 },
|
|
83
|
+
{ &Trampoline8, &TrampolineX8 },
|
|
84
|
+
{ &Trampoline9, &TrampolineX9 },
|
|
85
|
+
{ &Trampoline10, &TrampolineX10 },
|
|
86
|
+
{ &Trampoline11, &TrampolineX11 },
|
|
87
|
+
{ &Trampoline12, &TrampolineX12 },
|
|
88
|
+
{ &Trampoline13, &TrampolineX13 },
|
|
89
|
+
{ &Trampoline14, &TrampolineX14 },
|
|
90
|
+
{ &Trampoline15, &TrampolineX15 }
|
|
91
|
+
};
|
|
92
|
+
RG_STATIC_ASSERT(RG_LEN(Trampolines) == MaxTrampolines);
|
|
93
|
+
|
|
94
|
+
static RG_THREAD_LOCAL CallData *exec_call;
|
|
43
95
|
|
|
44
96
|
static inline int IsHFA(const TypeInfo *type)
|
|
45
97
|
{
|
|
@@ -74,7 +126,8 @@ bool AnalyseFunction(InstanceData *, FunctionInfo *func)
|
|
|
74
126
|
case PrimitiveKind::UInt64:
|
|
75
127
|
case PrimitiveKind::String:
|
|
76
128
|
case PrimitiveKind::String16:
|
|
77
|
-
case PrimitiveKind::Pointer:
|
|
129
|
+
case PrimitiveKind::Pointer:
|
|
130
|
+
case PrimitiveKind::Callback: {
|
|
78
131
|
#ifdef __APPLE__
|
|
79
132
|
if (param.variadic)
|
|
80
133
|
break;
|
|
@@ -208,8 +261,7 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
208
261
|
case PrimitiveKind::UInt16:
|
|
209
262
|
case PrimitiveKind::Int32:
|
|
210
263
|
case PrimitiveKind::UInt32:
|
|
211
|
-
case PrimitiveKind::Int64:
|
|
212
|
-
case PrimitiveKind::UInt64: {
|
|
264
|
+
case PrimitiveKind::Int64: {
|
|
213
265
|
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
214
266
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
|
|
215
267
|
return false;
|
|
@@ -218,10 +270,10 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
218
270
|
int64_t v = CopyNumber<int64_t>(value);
|
|
219
271
|
|
|
220
272
|
if (RG_LIKELY(param.gpr_count)) {
|
|
221
|
-
*(gpr_ptr++) =
|
|
273
|
+
*(int64_t *)(gpr_ptr++) = v;
|
|
222
274
|
} else {
|
|
223
275
|
args_ptr = AlignUp(args_ptr, param.type->align);
|
|
224
|
-
|
|
276
|
+
*(int64_t *)args_ptr = v;
|
|
225
277
|
#ifdef __APPLE__
|
|
226
278
|
args_ptr += param.type->size;
|
|
227
279
|
#else
|
|
@@ -229,6 +281,22 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
229
281
|
#endif
|
|
230
282
|
}
|
|
231
283
|
} break;
|
|
284
|
+
case PrimitiveKind::UInt64: {
|
|
285
|
+
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
286
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
uint64_t v = CopyNumber<uint64_t>(value);
|
|
291
|
+
|
|
292
|
+
if (RG_LIKELY(param.gpr_count)) {
|
|
293
|
+
*(gpr_ptr++) = v;
|
|
294
|
+
} else {
|
|
295
|
+
args_ptr = AlignUp(args_ptr, param.type->align);
|
|
296
|
+
*(uint64_t *)args_ptr = v;
|
|
297
|
+
args_ptr += 8;
|
|
298
|
+
}
|
|
299
|
+
} break;
|
|
232
300
|
case PrimitiveKind::String: {
|
|
233
301
|
const char *str;
|
|
234
302
|
if (RG_LIKELY(value.IsString())) {
|
|
@@ -365,10 +433,10 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
365
433
|
float f = CopyNumber<float>(value);
|
|
366
434
|
|
|
367
435
|
if (RG_LIKELY(param.vec_count)) {
|
|
368
|
-
|
|
436
|
+
*(float *)(vec_ptr++) = f;
|
|
369
437
|
} else {
|
|
370
438
|
args_ptr = AlignUp(args_ptr, 4);
|
|
371
|
-
|
|
439
|
+
*(float *)args_ptr = f;
|
|
372
440
|
#ifdef __APPLE__
|
|
373
441
|
args_ptr += 4;
|
|
374
442
|
#else
|
|
@@ -385,27 +453,57 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
385
453
|
double d = CopyNumber<double>(value);
|
|
386
454
|
|
|
387
455
|
if (RG_LIKELY(param.vec_count)) {
|
|
388
|
-
|
|
456
|
+
*(double *)(vec_ptr++) = d;
|
|
457
|
+
} else {
|
|
458
|
+
args_ptr = AlignUp(args_ptr, 8);
|
|
459
|
+
*(double *)args_ptr = d;
|
|
460
|
+
args_ptr += 8;
|
|
461
|
+
}
|
|
462
|
+
} break;
|
|
463
|
+
case PrimitiveKind::Callback: {
|
|
464
|
+
void *ptr;
|
|
465
|
+
|
|
466
|
+
if (value.IsFunction()) {
|
|
467
|
+
Napi::Function func = value.As<Napi::Function>();
|
|
468
|
+
|
|
469
|
+
Size idx = ReserveTrampoline(param.type->proto, func);
|
|
470
|
+
if (RG_UNLIKELY(idx < 0))
|
|
471
|
+
return false;
|
|
472
|
+
|
|
473
|
+
ptr = GetTrampoline(idx, param.type->proto);
|
|
474
|
+
} else if (CheckValueTag(instance, value, param.type)) {
|
|
475
|
+
ptr = value.As<Napi::External<void>>().Data();
|
|
476
|
+
} else if (IsNullOrUndefined(value)) {
|
|
477
|
+
ptr = nullptr;
|
|
478
|
+
} else {
|
|
479
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected %3", GetValueType(instance, value), i + 1, param.type->name);
|
|
480
|
+
return false;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
if (RG_LIKELY(param.gpr_count)) {
|
|
484
|
+
*(gpr_ptr++) = (uint64_t)ptr;
|
|
389
485
|
} else {
|
|
390
486
|
args_ptr = AlignUp(args_ptr, 8);
|
|
391
|
-
|
|
487
|
+
*(uint64_t *)args_ptr = (uint64_t)ptr;
|
|
392
488
|
args_ptr += 8;
|
|
393
489
|
}
|
|
394
490
|
} break;
|
|
395
491
|
}
|
|
396
492
|
}
|
|
397
493
|
|
|
398
|
-
|
|
494
|
+
new_sp = mem->stack.end();
|
|
399
495
|
|
|
400
496
|
return true;
|
|
401
497
|
}
|
|
402
498
|
|
|
403
499
|
void CallData::Execute()
|
|
404
500
|
{
|
|
501
|
+
exec_call = this;
|
|
502
|
+
|
|
405
503
|
#define PERFORM_CALL(Suffix) \
|
|
406
504
|
([&]() { \
|
|
407
|
-
auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func,
|
|
408
|
-
: ForwardCall ## Suffix(func->func,
|
|
505
|
+
auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, new_sp, &old_sp) \
|
|
506
|
+
: ForwardCall ## Suffix(func->func, new_sp, &old_sp)); \
|
|
409
507
|
return ret; \
|
|
410
508
|
})()
|
|
411
509
|
|
|
@@ -423,7 +521,8 @@ void CallData::Execute()
|
|
|
423
521
|
case PrimitiveKind::UInt64:
|
|
424
522
|
case PrimitiveKind::String:
|
|
425
523
|
case PrimitiveKind::String16:
|
|
426
|
-
case PrimitiveKind::Pointer:
|
|
524
|
+
case PrimitiveKind::Pointer:
|
|
525
|
+
case PrimitiveKind::Callback: { result.u64 = PERFORM_CALL(GG).x0; } break;
|
|
427
526
|
case PrimitiveKind::Record: {
|
|
428
527
|
if (func->ret.gpr_count) {
|
|
429
528
|
X0X1Ret ret = PERFORM_CALL(GG);
|
|
@@ -463,11 +562,16 @@ Napi::Value CallData::Complete()
|
|
|
463
562
|
case PrimitiveKind::UInt64: return Napi::BigInt::New(env, result.u64);
|
|
464
563
|
case PrimitiveKind::String: return Napi::String::New(env, (const char *)result.ptr);
|
|
465
564
|
case PrimitiveKind::String16: return Napi::String::New(env, (const char16_t *)result.ptr);
|
|
466
|
-
case PrimitiveKind::Pointer:
|
|
467
|
-
|
|
468
|
-
|
|
565
|
+
case PrimitiveKind::Pointer:
|
|
566
|
+
case PrimitiveKind::Callback: {
|
|
567
|
+
if (result.ptr) {
|
|
568
|
+
Napi::External<void> external = Napi::External<void>::New(env, result.ptr);
|
|
569
|
+
SetValueTag(instance, external, func->ret.type);
|
|
469
570
|
|
|
470
|
-
|
|
571
|
+
return external;
|
|
572
|
+
} else {
|
|
573
|
+
return env.Null();
|
|
574
|
+
}
|
|
471
575
|
} break;
|
|
472
576
|
case PrimitiveKind::Record: {
|
|
473
577
|
if (func->ret.vec_count) { // HFA
|
|
@@ -489,6 +593,437 @@ Napi::Value CallData::Complete()
|
|
|
489
593
|
RG_UNREACHABLE();
|
|
490
594
|
}
|
|
491
595
|
|
|
596
|
+
void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
|
|
597
|
+
{
|
|
598
|
+
const FunctionInfo *proto = instance->trampolines[idx].proto;
|
|
599
|
+
Napi::Function func = instance->trampolines[idx].func;
|
|
600
|
+
|
|
601
|
+
// Allow reuse of static trampoline
|
|
602
|
+
instance->free_trampolines |= 1u << idx;
|
|
603
|
+
used_trampolines &= ~(1u << idx);
|
|
604
|
+
|
|
605
|
+
uint64_t *gpr_ptr = (uint64_t *)own_sp;
|
|
606
|
+
uint64_t *vec_ptr = gpr_ptr + 9;
|
|
607
|
+
uint64_t *args_ptr = (uint64_t *)caller_sp;
|
|
608
|
+
|
|
609
|
+
uint8_t *return_ptr = proto->ret.use_memory ? (uint8_t *)gpr_ptr[8] : nullptr;
|
|
610
|
+
|
|
611
|
+
LocalArray<napi_value, MaxParameters> arguments;
|
|
612
|
+
|
|
613
|
+
// Convert to JS arguments
|
|
614
|
+
for (Size i = 0; i < proto->parameters.len; i++) {
|
|
615
|
+
const ParameterInfo ¶m = proto->parameters[i];
|
|
616
|
+
RG_ASSERT(param.directions >= 1 && param.directions <= 3);
|
|
617
|
+
|
|
618
|
+
switch (param.type->primitive) {
|
|
619
|
+
case PrimitiveKind::Void: { RG_UNREACHABLE(); } break;
|
|
620
|
+
|
|
621
|
+
case PrimitiveKind::Bool: {
|
|
622
|
+
#ifdef __APPLE__
|
|
623
|
+
bool b;
|
|
624
|
+
if (param.gpr_count) {
|
|
625
|
+
b = *(bool *)(gpr_ptr++);
|
|
626
|
+
} else {
|
|
627
|
+
b = *(bool *)args_ptr;
|
|
628
|
+
args_ptr = (uint64_t *)((uint8_t *)args_ptr + 1);
|
|
629
|
+
}
|
|
630
|
+
#else
|
|
631
|
+
bool b = *(bool *)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
632
|
+
#endif
|
|
633
|
+
|
|
634
|
+
Napi::Value arg = Napi::Boolean::New(env, b);
|
|
635
|
+
arguments.Append(arg);
|
|
636
|
+
} break;
|
|
637
|
+
case PrimitiveKind::Int8: {
|
|
638
|
+
#ifdef __APPLE__
|
|
639
|
+
double d;
|
|
640
|
+
if (param.gpr_count) {
|
|
641
|
+
d = (double)*(int8_t *)(gpr_ptr++);
|
|
642
|
+
} else {
|
|
643
|
+
d = (double)*(int8_t *)args_ptr;
|
|
644
|
+
args_ptr = (uint64_t *)((uint8_t *)args_ptr + 1);
|
|
645
|
+
}
|
|
646
|
+
#else
|
|
647
|
+
double d = (double)*(int8_t *)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
648
|
+
#endif
|
|
649
|
+
|
|
650
|
+
Napi::Value arg = Napi::Number::New(env, d);
|
|
651
|
+
arguments.Append(arg);
|
|
652
|
+
} break;
|
|
653
|
+
case PrimitiveKind::UInt8: {
|
|
654
|
+
#ifdef __APPLE__
|
|
655
|
+
double d;
|
|
656
|
+
if (param.gpr_count) {
|
|
657
|
+
d = (double)*(uint8_t *)(gpr_ptr++);
|
|
658
|
+
} else {
|
|
659
|
+
d = (double)*(uint8_t *)args_ptr;
|
|
660
|
+
args_ptr = (uint64_t *)((uint8_t *)args_ptr + 1);
|
|
661
|
+
}
|
|
662
|
+
#else
|
|
663
|
+
double d = (double)*(uint8_t *)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
664
|
+
#endif
|
|
665
|
+
|
|
666
|
+
Napi::Value arg = Napi::Number::New(env, d);
|
|
667
|
+
arguments.Append(arg);
|
|
668
|
+
} break;
|
|
669
|
+
case PrimitiveKind::Int16: {
|
|
670
|
+
#ifdef __APPLE__
|
|
671
|
+
double d;
|
|
672
|
+
if (param.gpr_count) {
|
|
673
|
+
d = (double)*(int16_t *)(gpr_ptr++);
|
|
674
|
+
} else {
|
|
675
|
+
args_ptr = AlignUp(args_ptr, 2);
|
|
676
|
+
d = (double)*(int16_t *)args_ptr;
|
|
677
|
+
args_ptr = (uint64_t *)((uint8_t *)args_ptr + 2);
|
|
678
|
+
}
|
|
679
|
+
#else
|
|
680
|
+
double d = (double)*(int16_t *)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
681
|
+
#endif
|
|
682
|
+
|
|
683
|
+
Napi::Value arg = Napi::Number::New(env, d);
|
|
684
|
+
arguments.Append(arg);
|
|
685
|
+
} break;
|
|
686
|
+
case PrimitiveKind::UInt16: {
|
|
687
|
+
#ifdef __APPLE__
|
|
688
|
+
double d;
|
|
689
|
+
if (param.gpr_count) {
|
|
690
|
+
d = (double)*(uint16_t *)(gpr_ptr++);
|
|
691
|
+
} else {
|
|
692
|
+
args_ptr = AlignUp(args_ptr, 2);
|
|
693
|
+
d = (double)*(uint16_t *)args_ptr;
|
|
694
|
+
args_ptr = (uint64_t *)((uint8_t *)args_ptr + 2);
|
|
695
|
+
}
|
|
696
|
+
#else
|
|
697
|
+
double d = (double)*(uint16_t *)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
698
|
+
#endif
|
|
699
|
+
|
|
700
|
+
Napi::Value arg = Napi::Number::New(env, d);
|
|
701
|
+
arguments.Append(arg);
|
|
702
|
+
} break;
|
|
703
|
+
case PrimitiveKind::Int32: {
|
|
704
|
+
#ifdef __APPLE__
|
|
705
|
+
double d;
|
|
706
|
+
if (param.gpr_count) {
|
|
707
|
+
d = (double)*(int32_t *)(gpr_ptr++);
|
|
708
|
+
} else {
|
|
709
|
+
args_ptr = AlignUp(args_ptr, 4);
|
|
710
|
+
d = (double)*(int32_t *)args_ptr;
|
|
711
|
+
args_ptr = (uint64_t *)((uint8_t *)args_ptr + 4);
|
|
712
|
+
}
|
|
713
|
+
#else
|
|
714
|
+
double d = (double)*(int32_t *)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
715
|
+
#endif
|
|
716
|
+
|
|
717
|
+
Napi::Value arg = Napi::Number::New(env, d);
|
|
718
|
+
arguments.Append(arg);
|
|
719
|
+
} break;
|
|
720
|
+
case PrimitiveKind::UInt32: {
|
|
721
|
+
#ifdef __APPLE__
|
|
722
|
+
double d;
|
|
723
|
+
if (param.gpr_count) {
|
|
724
|
+
d = (double)*(uint32_t *)(gpr_ptr++);
|
|
725
|
+
} else {
|
|
726
|
+
args_ptr = AlignUp(args_ptr, 4);
|
|
727
|
+
d = (double)*(uint32_t *)args_ptr;
|
|
728
|
+
args_ptr = (uint64_t *)((uint8_t *)args_ptr + 4);
|
|
729
|
+
}
|
|
730
|
+
#else
|
|
731
|
+
double d = (double)*(uint32_t *)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
732
|
+
#endif
|
|
733
|
+
|
|
734
|
+
Napi::Value arg = Napi::Number::New(env, d);
|
|
735
|
+
arguments.Append(arg);
|
|
736
|
+
} break;
|
|
737
|
+
case PrimitiveKind::Int64: {
|
|
738
|
+
#ifdef __APPLE__
|
|
739
|
+
args_ptr = AlignUp(args_ptr, 8);
|
|
740
|
+
#endif
|
|
741
|
+
|
|
742
|
+
int64_t v = *(int64_t *)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
743
|
+
|
|
744
|
+
Napi::Value arg = Napi::BigInt::New(env, v);
|
|
745
|
+
arguments.Append(arg);
|
|
746
|
+
} break;
|
|
747
|
+
case PrimitiveKind::UInt64: {
|
|
748
|
+
#ifdef __APPLE__
|
|
749
|
+
args_ptr = AlignUp(args_ptr, 8);
|
|
750
|
+
#endif
|
|
751
|
+
|
|
752
|
+
uint64_t v = *(uint64_t *)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
753
|
+
|
|
754
|
+
Napi::Value arg = Napi::BigInt::New(env, v);
|
|
755
|
+
arguments.Append(arg);
|
|
756
|
+
} break;
|
|
757
|
+
case PrimitiveKind::String: {
|
|
758
|
+
#ifdef __APPLE__
|
|
759
|
+
args_ptr = AlignUp(args_ptr, 8);
|
|
760
|
+
#endif
|
|
761
|
+
|
|
762
|
+
const char *str = *(const char **)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
763
|
+
|
|
764
|
+
Napi::Value arg = Napi::String::New(env, str);
|
|
765
|
+
arguments.Append(arg);
|
|
766
|
+
} break;
|
|
767
|
+
case PrimitiveKind::String16: {
|
|
768
|
+
#ifdef __APPLE__
|
|
769
|
+
args_ptr = AlignUp(args_ptr, 8);
|
|
770
|
+
#endif
|
|
771
|
+
|
|
772
|
+
const char16_t *str16 = *(const char16_t **)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
773
|
+
|
|
774
|
+
Napi::Value arg = Napi::String::New(env, str16);
|
|
775
|
+
arguments.Append(arg);
|
|
776
|
+
} break;
|
|
777
|
+
case PrimitiveKind::Pointer:
|
|
778
|
+
case PrimitiveKind::Callback: {
|
|
779
|
+
#ifdef __APPLE__
|
|
780
|
+
args_ptr = AlignUp(args_ptr, 8);
|
|
781
|
+
#endif
|
|
782
|
+
|
|
783
|
+
void *ptr2 = *(void **)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
784
|
+
|
|
785
|
+
if (ptr2) {
|
|
786
|
+
Napi::External<void> external = Napi::External<void>::New(env, ptr2);
|
|
787
|
+
SetValueTag(instance, external, param.type);
|
|
788
|
+
|
|
789
|
+
arguments.Append(external);
|
|
790
|
+
} else {
|
|
791
|
+
arguments.Append(env.Null());
|
|
792
|
+
}
|
|
793
|
+
} break;
|
|
794
|
+
case PrimitiveKind::Record: {
|
|
795
|
+
if (param.vec_count) { // HFA
|
|
796
|
+
Napi::Object obj = PopObject((uint8_t *)vec_ptr, param.type, 8);
|
|
797
|
+
arguments.Append(obj);
|
|
798
|
+
|
|
799
|
+
vec_ptr += param.vec_count;
|
|
800
|
+
} else if (!param.use_memory) {
|
|
801
|
+
if (param.gpr_count) {
|
|
802
|
+
RG_ASSERT(param.type->align <= 8);
|
|
803
|
+
|
|
804
|
+
Napi::Object obj = PopObject((uint8_t *)gpr_ptr, param.type);
|
|
805
|
+
arguments.Append(obj);
|
|
806
|
+
|
|
807
|
+
gpr_ptr += param.gpr_count;
|
|
808
|
+
} else if (param.type->size) {
|
|
809
|
+
args_ptr = AlignUp(args_ptr, param.type->align);
|
|
810
|
+
|
|
811
|
+
Napi::Object obj = PopObject((uint8_t *)args_ptr, param.type);
|
|
812
|
+
arguments.Append(obj);
|
|
813
|
+
|
|
814
|
+
args_ptr += (param.type->size + 7) / 8;
|
|
815
|
+
}
|
|
816
|
+
} else {
|
|
817
|
+
#ifdef __APPLE__
|
|
818
|
+
args_ptr = AlignUp(args_ptr, 8);
|
|
819
|
+
#endif
|
|
820
|
+
|
|
821
|
+
void *ptr2 = *(void **)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
822
|
+
|
|
823
|
+
Napi::Object obj = PopObject((uint8_t *)ptr2, param.type);
|
|
824
|
+
arguments.Append(obj);
|
|
825
|
+
}
|
|
826
|
+
} break;
|
|
827
|
+
case PrimitiveKind::Array: { RG_UNREACHABLE(); } break;
|
|
828
|
+
case PrimitiveKind::Float32: {
|
|
829
|
+
float f;
|
|
830
|
+
if (RG_LIKELY(param.vec_count)) {
|
|
831
|
+
f = *(float *)(vec_ptr++);
|
|
832
|
+
} else if (param.gpr_count) {
|
|
833
|
+
f = *(float *)(gpr_ptr++);
|
|
834
|
+
} else {
|
|
835
|
+
#ifdef __APPLE__
|
|
836
|
+
args_ptr = AlignUp(args_ptr, 4);
|
|
837
|
+
f = *(float *)args_ptr;
|
|
838
|
+
args_ptr = (uint64_t *)((uint8_t *)args_ptr + 4);
|
|
839
|
+
#else
|
|
840
|
+
f = *(float *)(args_ptr++);
|
|
841
|
+
#endif
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
Napi::Value arg = Napi::Number::New(env, (double)f);
|
|
845
|
+
arguments.Append(arg);
|
|
846
|
+
} break;
|
|
847
|
+
case PrimitiveKind::Float64: {
|
|
848
|
+
double d;
|
|
849
|
+
if (RG_LIKELY(param.vec_count)) {
|
|
850
|
+
d = *(double *)(vec_ptr++);
|
|
851
|
+
} else if (param.gpr_count) {
|
|
852
|
+
d = *(double *)(gpr_ptr++);
|
|
853
|
+
} else {
|
|
854
|
+
#ifdef __APPLE__
|
|
855
|
+
args_ptr = AlignUp(args_ptr, 8);
|
|
856
|
+
#endif
|
|
857
|
+
|
|
858
|
+
d = *(double *)(args_ptr++);
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
Napi::Value arg = Napi::Number::New(env, d);
|
|
862
|
+
arguments.Append(arg);
|
|
863
|
+
} break;
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
const TypeInfo *type = proto->ret.type;
|
|
868
|
+
|
|
869
|
+
// Make the call
|
|
870
|
+
napi_value ret = CallSwitchStack(&func, (size_t)arguments.len, arguments.data, old_sp, &mem->stack,
|
|
871
|
+
[](Napi::Function *func, size_t argc, napi_value *argv) { return (napi_value)func->Call(argc, argv); });
|
|
872
|
+
Napi::Value value(env, ret);
|
|
873
|
+
|
|
874
|
+
// Convert the result
|
|
875
|
+
switch (type->primitive) {
|
|
876
|
+
case PrimitiveKind::Void: {} break;
|
|
877
|
+
case PrimitiveKind::Bool: {
|
|
878
|
+
if (RG_UNLIKELY(!value.IsBoolean())) {
|
|
879
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected boolean", GetValueType(instance, value));
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
bool b = value.As<Napi::Boolean>();
|
|
884
|
+
out_reg->x0 = (uint64_t)b;
|
|
885
|
+
} break;
|
|
886
|
+
case PrimitiveKind::Int8:
|
|
887
|
+
case PrimitiveKind::UInt8:
|
|
888
|
+
case PrimitiveKind::Int16:
|
|
889
|
+
case PrimitiveKind::UInt16:
|
|
890
|
+
case PrimitiveKind::Int32:
|
|
891
|
+
case PrimitiveKind::UInt32:
|
|
892
|
+
case PrimitiveKind::Int64:
|
|
893
|
+
case PrimitiveKind::UInt64: {
|
|
894
|
+
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
895
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected number", GetValueType(instance, value));
|
|
896
|
+
return;
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
int64_t v = CopyNumber<int64_t>(value);
|
|
900
|
+
out_reg->x0 = (uint64_t)v;
|
|
901
|
+
} break;
|
|
902
|
+
case PrimitiveKind::String: {
|
|
903
|
+
const char *str;
|
|
904
|
+
if (RG_LIKELY(value.IsString())) {
|
|
905
|
+
str = PushString(value);
|
|
906
|
+
if (RG_UNLIKELY(!str))
|
|
907
|
+
return;
|
|
908
|
+
} else if (IsNullOrUndefined(value)) {
|
|
909
|
+
str = nullptr;
|
|
910
|
+
} else {
|
|
911
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected string", GetValueType(instance, value));
|
|
912
|
+
return;
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
out_reg->x0 = (uint64_t)str;
|
|
916
|
+
} break;
|
|
917
|
+
case PrimitiveKind::String16: {
|
|
918
|
+
const char16_t *str16;
|
|
919
|
+
if (RG_LIKELY(value.IsString())) {
|
|
920
|
+
str16 = PushString16(value);
|
|
921
|
+
if (RG_UNLIKELY(!str16))
|
|
922
|
+
return;
|
|
923
|
+
} else if (IsNullOrUndefined(value)) {
|
|
924
|
+
str16 = nullptr;
|
|
925
|
+
} else {
|
|
926
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected string", GetValueType(instance, value));
|
|
927
|
+
return;
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
out_reg->x0 = (uint64_t)str16;
|
|
931
|
+
} break;
|
|
932
|
+
case PrimitiveKind::Pointer: {
|
|
933
|
+
uint8_t *ptr;
|
|
934
|
+
|
|
935
|
+
if (CheckValueTag(instance, value, type)) {
|
|
936
|
+
ptr = value.As<Napi::External<uint8_t>>().Data();
|
|
937
|
+
} else if (IsObject(value) && type->ref->primitive == PrimitiveKind::Record) {
|
|
938
|
+
Napi::Object obj = value.As<Napi::Object>();
|
|
939
|
+
|
|
940
|
+
if (RG_UNLIKELY(!AllocHeap(type->ref->size, 16, &ptr)))
|
|
941
|
+
return;
|
|
942
|
+
|
|
943
|
+
if (!PushObject(obj, type->ref, ptr))
|
|
944
|
+
return;
|
|
945
|
+
} else if (IsNullOrUndefined(value)) {
|
|
946
|
+
ptr = nullptr;
|
|
947
|
+
} else {
|
|
948
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected %2", GetValueType(instance, value), type->name);
|
|
949
|
+
return;
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
out_reg->x0 = (uint64_t)ptr;
|
|
953
|
+
} break;
|
|
954
|
+
case PrimitiveKind::Record: {
|
|
955
|
+
if (RG_UNLIKELY(!IsObject(value))) {
|
|
956
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected object", GetValueType(instance, value));
|
|
957
|
+
return;
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
Napi::Object obj = value.As<Napi::Object>();
|
|
961
|
+
|
|
962
|
+
if (return_ptr) {
|
|
963
|
+
if (!PushObject(obj, type, return_ptr))
|
|
964
|
+
return;
|
|
965
|
+
out_reg->x0 = (uint64_t)return_ptr;
|
|
966
|
+
} else if (proto->ret.vec_count) { // HFA
|
|
967
|
+
PushObject(obj, type, (uint8_t *)&out_reg->d0, 8);
|
|
968
|
+
} else {
|
|
969
|
+
PushObject(obj, type, (uint8_t *)&out_reg->x0);
|
|
970
|
+
}
|
|
971
|
+
} break;
|
|
972
|
+
case PrimitiveKind::Array: { RG_UNREACHABLE(); } break;
|
|
973
|
+
case PrimitiveKind::Float32: {
|
|
974
|
+
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
975
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected number", GetValueType(instance, value));
|
|
976
|
+
return;
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
float f = CopyNumber<float>(value);
|
|
980
|
+
memcpy(&out_reg->d0, &f, 4);
|
|
981
|
+
} break;
|
|
982
|
+
case PrimitiveKind::Float64: {
|
|
983
|
+
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
984
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected number", GetValueType(instance, value));
|
|
985
|
+
return;
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
double d = CopyNumber<double>(value);
|
|
989
|
+
out_reg->d0 = d;
|
|
990
|
+
} break;
|
|
991
|
+
case PrimitiveKind::Callback: {
|
|
992
|
+
void *ptr;
|
|
993
|
+
|
|
994
|
+
if (value.IsFunction()) {
|
|
995
|
+
Napi::Function func = value.As<Napi::Function>();
|
|
996
|
+
|
|
997
|
+
Size idx = ReserveTrampoline(type->proto, func);
|
|
998
|
+
if (RG_UNLIKELY(idx < 0))
|
|
999
|
+
return;
|
|
1000
|
+
|
|
1001
|
+
ptr = GetTrampoline(idx, type->proto);
|
|
1002
|
+
} else if (CheckValueTag(instance, value, type)) {
|
|
1003
|
+
ptr = value.As<Napi::External<uint8_t>>().Data();
|
|
1004
|
+
} else if (IsNullOrUndefined(value)) {
|
|
1005
|
+
ptr = nullptr;
|
|
1006
|
+
} else {
|
|
1007
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected %2", GetValueType(instance, value), type->name);
|
|
1008
|
+
return;
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
out_reg->x0 = (uint64_t)ptr;
|
|
1012
|
+
} break;
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
void *GetTrampoline(Size idx, const FunctionInfo *proto)
|
|
1017
|
+
{
|
|
1018
|
+
bool vec = proto->forward_fp || IsFloat(proto->ret.type);
|
|
1019
|
+
return Trampolines[idx][vec];
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
extern "C" void RelayCallBack(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
|
|
1023
|
+
{
|
|
1024
|
+
exec_call->Relay(idx, own_sp, caller_sp, out_reg);
|
|
1025
|
+
}
|
|
1026
|
+
|
|
492
1027
|
}
|
|
493
1028
|
|
|
494
1029
|
#endif
|