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_x64_sysv.cc
CHANGED
|
@@ -46,17 +46,67 @@ struct Xmm0Xmm1Ret {
|
|
|
46
46
|
double xmm1;
|
|
47
47
|
};
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
extern "C"
|
|
57
|
-
extern "C"
|
|
58
|
-
extern "C"
|
|
59
|
-
extern "C"
|
|
49
|
+
struct BackRegisters {
|
|
50
|
+
uint64_t rax;
|
|
51
|
+
uint64_t rdx;
|
|
52
|
+
double xmm0;
|
|
53
|
+
double xmm1;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
extern "C" RaxRdxRet ForwardCallGG(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
57
|
+
extern "C" float ForwardCallF(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
58
|
+
extern "C" Xmm0RaxRet ForwardCallDG(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
59
|
+
extern "C" RaxXmm0Ret ForwardCallGD(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
60
|
+
extern "C" Xmm0Xmm1Ret ForwardCallDD(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
61
|
+
|
|
62
|
+
extern "C" RaxRdxRet ForwardCallXGG(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
63
|
+
extern "C" float ForwardCallXF(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
64
|
+
extern "C" Xmm0RaxRet ForwardCallXDG(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
65
|
+
extern "C" RaxXmm0Ret ForwardCallXGD(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
66
|
+
extern "C" Xmm0Xmm1Ret ForwardCallXDD(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
67
|
+
|
|
68
|
+
extern "C" int Trampoline0; extern "C" int TrampolineX0;
|
|
69
|
+
extern "C" int Trampoline1; extern "C" int TrampolineX1;
|
|
70
|
+
extern "C" int Trampoline2; extern "C" int TrampolineX2;
|
|
71
|
+
extern "C" int Trampoline3; extern "C" int TrampolineX3;
|
|
72
|
+
extern "C" int Trampoline4; extern "C" int TrampolineX4;
|
|
73
|
+
extern "C" int Trampoline5; extern "C" int TrampolineX5;
|
|
74
|
+
extern "C" int Trampoline6; extern "C" int TrampolineX6;
|
|
75
|
+
extern "C" int Trampoline7; extern "C" int TrampolineX7;
|
|
76
|
+
extern "C" int Trampoline8; extern "C" int TrampolineX8;
|
|
77
|
+
extern "C" int Trampoline9; extern "C" int TrampolineX9;
|
|
78
|
+
extern "C" int Trampoline10; extern "C" int TrampolineX10;
|
|
79
|
+
extern "C" int Trampoline11; extern "C" int TrampolineX11;
|
|
80
|
+
extern "C" int Trampoline12; extern "C" int TrampolineX12;
|
|
81
|
+
extern "C" int Trampoline13; extern "C" int TrampolineX13;
|
|
82
|
+
extern "C" int Trampoline14; extern "C" int TrampolineX14;
|
|
83
|
+
extern "C" int Trampoline15; extern "C" int TrampolineX15;
|
|
84
|
+
|
|
85
|
+
extern "C" napi_value CallSwitchStack(Napi::Function *func, size_t argc, napi_value *argv,
|
|
86
|
+
uint8_t *old_sp, Span<uint8_t> *new_stack,
|
|
87
|
+
napi_value (*call)(Napi::Function *func, size_t argc, napi_value *argv));
|
|
88
|
+
|
|
89
|
+
static void *const Trampolines[][2] = {
|
|
90
|
+
{ &Trampoline0, &TrampolineX0 },
|
|
91
|
+
{ &Trampoline1, &TrampolineX1 },
|
|
92
|
+
{ &Trampoline2, &TrampolineX2 },
|
|
93
|
+
{ &Trampoline3, &TrampolineX3 },
|
|
94
|
+
{ &Trampoline4, &TrampolineX4 },
|
|
95
|
+
{ &Trampoline5, &TrampolineX5 },
|
|
96
|
+
{ &Trampoline6, &TrampolineX6 },
|
|
97
|
+
{ &Trampoline7, &TrampolineX7 },
|
|
98
|
+
{ &Trampoline8, &TrampolineX8 },
|
|
99
|
+
{ &Trampoline9, &TrampolineX9 },
|
|
100
|
+
{ &Trampoline10, &TrampolineX10 },
|
|
101
|
+
{ &Trampoline11, &TrampolineX11 },
|
|
102
|
+
{ &Trampoline12, &TrampolineX12 },
|
|
103
|
+
{ &Trampoline13, &TrampolineX13 },
|
|
104
|
+
{ &Trampoline14, &TrampolineX14 },
|
|
105
|
+
{ &Trampoline15, &TrampolineX15 }
|
|
106
|
+
};
|
|
107
|
+
RG_STATIC_ASSERT(RG_LEN(Trampolines) == MaxTrampolines);
|
|
108
|
+
|
|
109
|
+
static RG_THREAD_LOCAL CallData *exec_call;
|
|
60
110
|
|
|
61
111
|
static inline RegisterClass MergeClasses(RegisterClass cls1, RegisterClass cls2)
|
|
62
112
|
{
|
|
@@ -94,7 +144,8 @@ static Size ClassifyType(const TypeInfo *type, Size offset, Span<RegisterClass>
|
|
|
94
144
|
case PrimitiveKind::UInt64:
|
|
95
145
|
case PrimitiveKind::String:
|
|
96
146
|
case PrimitiveKind::String16:
|
|
97
|
-
case PrimitiveKind::Pointer:
|
|
147
|
+
case PrimitiveKind::Pointer:
|
|
148
|
+
case PrimitiveKind::Callback: {
|
|
98
149
|
classes[0] = MergeClasses(classes[0], RegisterClass::Integer);
|
|
99
150
|
return 1;
|
|
100
151
|
} break;
|
|
@@ -197,7 +248,7 @@ bool AnalyseFunction(InstanceData *, FunctionInfo *func)
|
|
|
197
248
|
|
|
198
249
|
bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
199
250
|
{
|
|
200
|
-
|
|
251
|
+
uint64_t *args_ptr = nullptr;
|
|
201
252
|
uint64_t *gpr_ptr = nullptr;
|
|
202
253
|
uint64_t *xmm_ptr = nullptr;
|
|
203
254
|
|
|
@@ -231,13 +282,7 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
231
282
|
}
|
|
232
283
|
|
|
233
284
|
bool b = value.As<Napi::Boolean>();
|
|
234
|
-
|
|
235
|
-
if (RG_LIKELY(param.gpr_count)) {
|
|
236
|
-
*(gpr_ptr++) = (uint64_t)b;
|
|
237
|
-
} else {
|
|
238
|
-
*args_ptr = (uint8_t)b;
|
|
239
|
-
args_ptr += 8;
|
|
240
|
-
}
|
|
285
|
+
*((param.gpr_count ? gpr_ptr : args_ptr)++) = (uint64_t)b;
|
|
241
286
|
} break;
|
|
242
287
|
case PrimitiveKind::Int8:
|
|
243
288
|
case PrimitiveKind::UInt8:
|
|
@@ -245,22 +290,23 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
245
290
|
case PrimitiveKind::UInt16:
|
|
246
291
|
case PrimitiveKind::Int32:
|
|
247
292
|
case PrimitiveKind::UInt32:
|
|
248
|
-
case PrimitiveKind::Int64:
|
|
249
|
-
case PrimitiveKind::UInt64: {
|
|
293
|
+
case PrimitiveKind::Int64: {
|
|
250
294
|
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
251
295
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
|
|
252
296
|
return false;
|
|
253
297
|
}
|
|
254
298
|
|
|
255
299
|
int64_t v = CopyNumber<int64_t>(value);
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
args_ptr += 8;
|
|
300
|
+
*(int64_t *)((param.gpr_count ? gpr_ptr : args_ptr)++) = v;
|
|
301
|
+
} break;
|
|
302
|
+
case PrimitiveKind::UInt64: {
|
|
303
|
+
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
304
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
|
|
305
|
+
return false;
|
|
263
306
|
}
|
|
307
|
+
|
|
308
|
+
uint64_t v = CopyNumber<uint64_t>(value);
|
|
309
|
+
*((param.gpr_count ? gpr_ptr : args_ptr)++) = v;
|
|
264
310
|
} break;
|
|
265
311
|
case PrimitiveKind::String: {
|
|
266
312
|
const char *str;
|
|
@@ -275,13 +321,7 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
275
321
|
return false;
|
|
276
322
|
}
|
|
277
323
|
|
|
278
|
-
|
|
279
|
-
*(gpr_ptr++) = (uint64_t)str;
|
|
280
|
-
} else {
|
|
281
|
-
args_ptr = AlignUp(args_ptr, 8);
|
|
282
|
-
*(uint64_t *)args_ptr = (uint64_t)str;
|
|
283
|
-
args_ptr += 8;
|
|
284
|
-
}
|
|
324
|
+
*(const char **)((param.gpr_count ? gpr_ptr : args_ptr)++) = str;
|
|
285
325
|
} break;
|
|
286
326
|
case PrimitiveKind::String16: {
|
|
287
327
|
const char16_t *str16;
|
|
@@ -296,13 +336,7 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
296
336
|
return false;
|
|
297
337
|
}
|
|
298
338
|
|
|
299
|
-
|
|
300
|
-
*(gpr_ptr++) = (uint64_t)str16;
|
|
301
|
-
} else {
|
|
302
|
-
args_ptr = AlignUp(args_ptr, 8);
|
|
303
|
-
*(uint64_t *)args_ptr = (uint64_t)str16;
|
|
304
|
-
args_ptr += 8;
|
|
305
|
-
}
|
|
339
|
+
*(const char16_t **)((param.gpr_count ? gpr_ptr : args_ptr)++) = str16;
|
|
306
340
|
} break;
|
|
307
341
|
case PrimitiveKind::Pointer: {
|
|
308
342
|
uint8_t *ptr;
|
|
@@ -335,13 +369,7 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
335
369
|
return false;
|
|
336
370
|
}
|
|
337
371
|
|
|
338
|
-
|
|
339
|
-
*(gpr_ptr++) = (uint64_t)ptr;
|
|
340
|
-
} else {
|
|
341
|
-
args_ptr = AlignUp(args_ptr, 8);
|
|
342
|
-
*(uint64_t *)args_ptr = (uint64_t)ptr;
|
|
343
|
-
args_ptr += 8;
|
|
344
|
-
}
|
|
372
|
+
*(void **)((param.gpr_count ? gpr_ptr : args_ptr)++) = ptr;
|
|
345
373
|
} break;
|
|
346
374
|
case PrimitiveKind::Record: {
|
|
347
375
|
if (RG_UNLIKELY(!IsObject(value))) {
|
|
@@ -357,10 +385,9 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
357
385
|
uint64_t buf[2] = {};
|
|
358
386
|
if (!PushObject(obj, param.type, (uint8_t *)buf))
|
|
359
387
|
return false;
|
|
388
|
+
uint64_t *ptr = buf;
|
|
360
389
|
|
|
361
390
|
if (param.gpr_first) {
|
|
362
|
-
uint64_t *ptr = buf;
|
|
363
|
-
|
|
364
391
|
*(gpr_ptr++) = *(ptr++);
|
|
365
392
|
if (param.gpr_count == 2) {
|
|
366
393
|
*(gpr_ptr++) = *(ptr++);
|
|
@@ -368,8 +395,6 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
368
395
|
*(xmm_ptr++) = *(ptr++);
|
|
369
396
|
}
|
|
370
397
|
} else {
|
|
371
|
-
uint64_t *ptr = buf;
|
|
372
|
-
|
|
373
398
|
*(xmm_ptr++) = *(ptr++);
|
|
374
399
|
if (param.xmm_count == 2) {
|
|
375
400
|
*(xmm_ptr++) = *(ptr++);
|
|
@@ -379,9 +404,9 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
379
404
|
}
|
|
380
405
|
} else if (param.use_memory) {
|
|
381
406
|
args_ptr = AlignUp(args_ptr, param.type->align);
|
|
382
|
-
if (!PushObject(obj, param.type, args_ptr))
|
|
407
|
+
if (!PushObject(obj, param.type, (uint8_t *)args_ptr))
|
|
383
408
|
return false;
|
|
384
|
-
args_ptr +=
|
|
409
|
+
args_ptr += (param.type->size + 7) / 8;
|
|
385
410
|
}
|
|
386
411
|
} break;
|
|
387
412
|
case PrimitiveKind::Array: { RG_UNREACHABLE(); } break;
|
|
@@ -392,14 +417,7 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
392
417
|
}
|
|
393
418
|
|
|
394
419
|
float f = CopyNumber<float>(value);
|
|
395
|
-
|
|
396
|
-
if (RG_LIKELY(param.xmm_count)) {
|
|
397
|
-
memcpy(xmm_ptr++, &f, 4);
|
|
398
|
-
} else {
|
|
399
|
-
args_ptr = AlignUp(args_ptr, 4);
|
|
400
|
-
memcpy(args_ptr, &f, 4);
|
|
401
|
-
args_ptr += 8;
|
|
402
|
-
}
|
|
420
|
+
*(float *)((param.xmm_count ? xmm_ptr : args_ptr)++) = f;
|
|
403
421
|
} break;
|
|
404
422
|
case PrimitiveKind::Float64: {
|
|
405
423
|
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
@@ -408,29 +426,46 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
408
426
|
}
|
|
409
427
|
|
|
410
428
|
double d = CopyNumber<double>(value);
|
|
429
|
+
*(double *)((param.xmm_count ? xmm_ptr : args_ptr)++) = d;
|
|
430
|
+
} break;
|
|
431
|
+
case PrimitiveKind::Callback: {
|
|
432
|
+
void *ptr;
|
|
433
|
+
|
|
434
|
+
if (value.IsFunction()) {
|
|
435
|
+
Napi::Function func = value.As<Napi::Function>();
|
|
411
436
|
|
|
412
|
-
|
|
413
|
-
|
|
437
|
+
Size idx = ReserveTrampoline(param.type->proto, func);
|
|
438
|
+
if (RG_UNLIKELY(idx < 0))
|
|
439
|
+
return false;
|
|
440
|
+
|
|
441
|
+
ptr = GetTrampoline(idx, param.type->proto);
|
|
442
|
+
} else if (CheckValueTag(instance, value, param.type)) {
|
|
443
|
+
ptr = value.As<Napi::External<void>>().Data();
|
|
444
|
+
} else if (IsNullOrUndefined(value)) {
|
|
445
|
+
ptr = nullptr;
|
|
414
446
|
} else {
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
args_ptr += 8;
|
|
447
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected %3", GetValueType(instance, value), i + 1, param.type->name);
|
|
448
|
+
return false;
|
|
418
449
|
}
|
|
450
|
+
|
|
451
|
+
*(void **)((param.gpr_count ? gpr_ptr : args_ptr)++) = ptr;
|
|
419
452
|
} break;
|
|
420
453
|
}
|
|
421
454
|
}
|
|
422
455
|
|
|
423
|
-
|
|
456
|
+
new_sp = mem->stack.end();
|
|
424
457
|
|
|
425
458
|
return true;
|
|
426
459
|
}
|
|
427
460
|
|
|
428
461
|
void CallData::Execute()
|
|
429
462
|
{
|
|
463
|
+
exec_call = this;
|
|
464
|
+
|
|
430
465
|
#define PERFORM_CALL(Suffix) \
|
|
431
466
|
([&]() { \
|
|
432
|
-
auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func,
|
|
433
|
-
: ForwardCall ## Suffix(func->func,
|
|
467
|
+
auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, new_sp, &old_sp) \
|
|
468
|
+
: ForwardCall ## Suffix(func->func, new_sp, &old_sp)); \
|
|
434
469
|
return ret; \
|
|
435
470
|
})()
|
|
436
471
|
|
|
@@ -448,7 +483,8 @@ void CallData::Execute()
|
|
|
448
483
|
case PrimitiveKind::UInt64:
|
|
449
484
|
case PrimitiveKind::String:
|
|
450
485
|
case PrimitiveKind::String16:
|
|
451
|
-
case PrimitiveKind::Pointer:
|
|
486
|
+
case PrimitiveKind::Pointer:
|
|
487
|
+
case PrimitiveKind::Callback: { result.u64 = PERFORM_CALL(GG).rax; } break;
|
|
452
488
|
case PrimitiveKind::Record: {
|
|
453
489
|
if (func->ret.gpr_first && !func->ret.xmm_count) {
|
|
454
490
|
RaxRdxRet ret = PERFORM_CALL(GG);
|
|
@@ -492,11 +528,16 @@ Napi::Value CallData::Complete()
|
|
|
492
528
|
case PrimitiveKind::UInt64: return Napi::BigInt::New(env, result.u64);
|
|
493
529
|
case PrimitiveKind::String: return Napi::String::New(env, (const char *)result.ptr);
|
|
494
530
|
case PrimitiveKind::String16: return Napi::String::New(env, (const char16_t *)result.ptr);
|
|
495
|
-
case PrimitiveKind::Pointer:
|
|
496
|
-
|
|
497
|
-
|
|
531
|
+
case PrimitiveKind::Pointer:
|
|
532
|
+
case PrimitiveKind::Callback: {
|
|
533
|
+
if (result.ptr) {
|
|
534
|
+
Napi::External<void> external = Napi::External<void>::New(env, result.ptr);
|
|
535
|
+
SetValueTag(instance, external, func->ret.type);
|
|
498
536
|
|
|
499
|
-
|
|
537
|
+
return external;
|
|
538
|
+
} else {
|
|
539
|
+
return env.Null();
|
|
540
|
+
}
|
|
500
541
|
} break;
|
|
501
542
|
case PrimitiveKind::Record: {
|
|
502
543
|
const uint8_t *ptr = return_ptr ? (const uint8_t *)return_ptr
|
|
@@ -513,6 +554,337 @@ Napi::Value CallData::Complete()
|
|
|
513
554
|
RG_UNREACHABLE();
|
|
514
555
|
}
|
|
515
556
|
|
|
557
|
+
void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
|
|
558
|
+
{
|
|
559
|
+
const FunctionInfo *proto = instance->trampolines[idx].proto;
|
|
560
|
+
Napi::Function func = instance->trampolines[idx].func;
|
|
561
|
+
|
|
562
|
+
// Allow reuse of static trampoline
|
|
563
|
+
instance->free_trampolines |= 1u << idx;
|
|
564
|
+
used_trampolines &= ~(1u << idx);
|
|
565
|
+
|
|
566
|
+
uint64_t *gpr_ptr = (uint64_t *)own_sp;
|
|
567
|
+
uint64_t *xmm_ptr = gpr_ptr + 6;
|
|
568
|
+
uint64_t *args_ptr = (uint64_t *)caller_sp;
|
|
569
|
+
|
|
570
|
+
uint8_t *return_ptr = proto->ret.use_memory ? (uint8_t *)gpr_ptr[0] : nullptr;
|
|
571
|
+
gpr_ptr += proto->ret.use_memory;
|
|
572
|
+
|
|
573
|
+
LocalArray<napi_value, MaxParameters> arguments;
|
|
574
|
+
|
|
575
|
+
// Convert to JS arguments
|
|
576
|
+
for (Size i = 0; i < proto->parameters.len; i++) {
|
|
577
|
+
const ParameterInfo ¶m = proto->parameters[i];
|
|
578
|
+
RG_ASSERT(param.directions >= 1 && param.directions <= 3);
|
|
579
|
+
|
|
580
|
+
switch (param.type->primitive) {
|
|
581
|
+
case PrimitiveKind::Void: { RG_UNREACHABLE(); } break;
|
|
582
|
+
|
|
583
|
+
case PrimitiveKind::Bool: {
|
|
584
|
+
bool b = *(bool *)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
585
|
+
|
|
586
|
+
Napi::Value arg = Napi::Boolean::New(env, b);
|
|
587
|
+
arguments.Append(arg);
|
|
588
|
+
} break;
|
|
589
|
+
case PrimitiveKind::Int8: {
|
|
590
|
+
double d = (double)*(int8_t *)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
591
|
+
|
|
592
|
+
Napi::Value arg = Napi::Number::New(env, d);
|
|
593
|
+
arguments.Append(arg);
|
|
594
|
+
} break;
|
|
595
|
+
case PrimitiveKind::UInt8: {
|
|
596
|
+
double d = (double)*(uint8_t *)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
597
|
+
|
|
598
|
+
Napi::Value arg = Napi::Number::New(env, d);
|
|
599
|
+
arguments.Append(arg);
|
|
600
|
+
} break;
|
|
601
|
+
case PrimitiveKind::Int16: {
|
|
602
|
+
double d = (double)*(int16_t *)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
603
|
+
|
|
604
|
+
Napi::Value arg = Napi::Number::New(env, d);
|
|
605
|
+
arguments.Append(arg);
|
|
606
|
+
} break;
|
|
607
|
+
case PrimitiveKind::UInt16: {
|
|
608
|
+
double d = (double)*(uint16_t *)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
609
|
+
|
|
610
|
+
Napi::Value arg = Napi::Number::New(env, d);
|
|
611
|
+
arguments.Append(arg);
|
|
612
|
+
} break;
|
|
613
|
+
case PrimitiveKind::Int32: {
|
|
614
|
+
double d = (double)*(int32_t *)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
615
|
+
|
|
616
|
+
Napi::Value arg = Napi::Number::New(env, d);
|
|
617
|
+
arguments.Append(arg);
|
|
618
|
+
} break;
|
|
619
|
+
case PrimitiveKind::UInt32: {
|
|
620
|
+
double d = (double)*(int32_t *)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
621
|
+
|
|
622
|
+
Napi::Value arg = Napi::Number::New(env, d);
|
|
623
|
+
arguments.Append(arg);
|
|
624
|
+
} break;
|
|
625
|
+
case PrimitiveKind::Int64: {
|
|
626
|
+
int64_t v = *(int64_t *)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
627
|
+
|
|
628
|
+
Napi::Value arg = Napi::BigInt::New(env, v);
|
|
629
|
+
arguments.Append(arg);
|
|
630
|
+
} break;
|
|
631
|
+
case PrimitiveKind::UInt64: {
|
|
632
|
+
uint64_t v = *(uint64_t *)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
633
|
+
|
|
634
|
+
Napi::Value arg = Napi::BigInt::New(env, v);
|
|
635
|
+
arguments.Append(arg);
|
|
636
|
+
} break;
|
|
637
|
+
case PrimitiveKind::String: {
|
|
638
|
+
const char *str = *(const char **)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
639
|
+
|
|
640
|
+
Napi::Value arg = Napi::String::New(env, str);
|
|
641
|
+
arguments.Append(arg);
|
|
642
|
+
} break;
|
|
643
|
+
case PrimitiveKind::String16: {
|
|
644
|
+
const char16_t *str16 = *(const char16_t **)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
645
|
+
|
|
646
|
+
Napi::Value arg = Napi::String::New(env, str16);
|
|
647
|
+
arguments.Append(arg);
|
|
648
|
+
} break;
|
|
649
|
+
case PrimitiveKind::Pointer:
|
|
650
|
+
case PrimitiveKind::Callback: {
|
|
651
|
+
void *ptr2 = *(void **)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
652
|
+
|
|
653
|
+
if (ptr2) {
|
|
654
|
+
Napi::External<void> external = Napi::External<void>::New(env, ptr2);
|
|
655
|
+
SetValueTag(instance, external, param.type);
|
|
656
|
+
|
|
657
|
+
arguments.Append(external);
|
|
658
|
+
} else {
|
|
659
|
+
arguments.Append(env.Null());
|
|
660
|
+
}
|
|
661
|
+
} break;
|
|
662
|
+
case PrimitiveKind::Record: {
|
|
663
|
+
if (param.gpr_count || param.xmm_count) {
|
|
664
|
+
RG_ASSERT(param.type->size <= 16);
|
|
665
|
+
|
|
666
|
+
uint64_t buf[2] = {};
|
|
667
|
+
uint64_t *ptr = buf;
|
|
668
|
+
|
|
669
|
+
if (param.gpr_first) {
|
|
670
|
+
*(ptr++) = *(gpr_ptr++);
|
|
671
|
+
if (param.gpr_count == 2) {
|
|
672
|
+
*(ptr++) = *(gpr_ptr++);
|
|
673
|
+
} else if (param.xmm_count == 1) {
|
|
674
|
+
*(ptr++) = *(xmm_ptr++);
|
|
675
|
+
}
|
|
676
|
+
} else {
|
|
677
|
+
*(ptr++) = *(xmm_ptr++);
|
|
678
|
+
if (param.xmm_count == 2) {
|
|
679
|
+
*(ptr++) = *(xmm_ptr++);
|
|
680
|
+
} else if (param.gpr_count == 1) {
|
|
681
|
+
*(ptr++) = *(gpr_ptr++);
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
Napi::Object obj = PopObject((const uint8_t *)buf, param.type);
|
|
686
|
+
arguments.Append(obj);
|
|
687
|
+
} else if (param.use_memory) {
|
|
688
|
+
args_ptr = AlignUp(args_ptr, param.type->align);
|
|
689
|
+
|
|
690
|
+
Napi::Object obj = PopObject((const uint8_t *)args_ptr, param.type);
|
|
691
|
+
arguments.Append(obj);
|
|
692
|
+
|
|
693
|
+
args_ptr += (param.type->size + 7) / 8;
|
|
694
|
+
}
|
|
695
|
+
} break;
|
|
696
|
+
case PrimitiveKind::Array: { RG_UNREACHABLE(); } break;
|
|
697
|
+
case PrimitiveKind::Float32: {
|
|
698
|
+
float f = *(float *)((param.xmm_count ? xmm_ptr : args_ptr)++);
|
|
699
|
+
|
|
700
|
+
Napi::Value arg = Napi::Number::New(env, (double)f);
|
|
701
|
+
arguments.Append(arg);
|
|
702
|
+
} break;
|
|
703
|
+
case PrimitiveKind::Float64: {
|
|
704
|
+
double d = *(double *)((param.xmm_count ? xmm_ptr : args_ptr)++);
|
|
705
|
+
|
|
706
|
+
Napi::Value arg = Napi::Number::New(env, d);
|
|
707
|
+
arguments.Append(arg);
|
|
708
|
+
} break;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
const TypeInfo *type = proto->ret.type;
|
|
713
|
+
|
|
714
|
+
// Make the call
|
|
715
|
+
napi_value ret = CallSwitchStack(&func, (size_t)arguments.len, arguments.data, old_sp, &mem->stack,
|
|
716
|
+
[](Napi::Function *func, size_t argc, napi_value *argv) { return (napi_value)func->Call(argc, argv); });
|
|
717
|
+
Napi::Value value(env, ret);
|
|
718
|
+
|
|
719
|
+
// Convert the result
|
|
720
|
+
switch (type->primitive) {
|
|
721
|
+
case PrimitiveKind::Void: {} break;
|
|
722
|
+
case PrimitiveKind::Bool: {
|
|
723
|
+
if (RG_UNLIKELY(!value.IsBoolean())) {
|
|
724
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected boolean", GetValueType(instance, value));
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
bool b = value.As<Napi::Boolean>();
|
|
729
|
+
out_reg->rax = (uint64_t)b;
|
|
730
|
+
} break;
|
|
731
|
+
case PrimitiveKind::Int8:
|
|
732
|
+
case PrimitiveKind::UInt8:
|
|
733
|
+
case PrimitiveKind::Int16:
|
|
734
|
+
case PrimitiveKind::UInt16:
|
|
735
|
+
case PrimitiveKind::Int32:
|
|
736
|
+
case PrimitiveKind::UInt32:
|
|
737
|
+
case PrimitiveKind::Int64:
|
|
738
|
+
case PrimitiveKind::UInt64: {
|
|
739
|
+
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
740
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected number", GetValueType(instance, value));
|
|
741
|
+
return;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
int64_t v = CopyNumber<int64_t>(value);
|
|
745
|
+
out_reg->rax = (uint64_t)v;
|
|
746
|
+
} break;
|
|
747
|
+
case PrimitiveKind::String: {
|
|
748
|
+
const char *str;
|
|
749
|
+
if (RG_LIKELY(value.IsString())) {
|
|
750
|
+
str = PushString(value);
|
|
751
|
+
if (RG_UNLIKELY(!str))
|
|
752
|
+
return;
|
|
753
|
+
} else if (IsNullOrUndefined(value)) {
|
|
754
|
+
str = nullptr;
|
|
755
|
+
} else {
|
|
756
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected string", GetValueType(instance, value));
|
|
757
|
+
return;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
out_reg->rax = (uint64_t)str;
|
|
761
|
+
} break;
|
|
762
|
+
case PrimitiveKind::String16: {
|
|
763
|
+
const char16_t *str16;
|
|
764
|
+
if (RG_LIKELY(value.IsString())) {
|
|
765
|
+
str16 = PushString16(value);
|
|
766
|
+
if (RG_UNLIKELY(!str16))
|
|
767
|
+
return;
|
|
768
|
+
} else if (IsNullOrUndefined(value)) {
|
|
769
|
+
str16 = nullptr;
|
|
770
|
+
} else {
|
|
771
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected string", GetValueType(instance, value));
|
|
772
|
+
return;
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
out_reg->rax = (uint64_t)str16;
|
|
776
|
+
} break;
|
|
777
|
+
case PrimitiveKind::Pointer: {
|
|
778
|
+
uint8_t *ptr;
|
|
779
|
+
|
|
780
|
+
if (CheckValueTag(instance, value, type)) {
|
|
781
|
+
ptr = value.As<Napi::External<uint8_t>>().Data();
|
|
782
|
+
} else if (IsObject(value) && type->ref->primitive == PrimitiveKind::Record) {
|
|
783
|
+
Napi::Object obj = value.As<Napi::Object>();
|
|
784
|
+
|
|
785
|
+
if (RG_UNLIKELY(!AllocHeap(type->ref->size, 16, &ptr)))
|
|
786
|
+
return;
|
|
787
|
+
|
|
788
|
+
if (!PushObject(obj, type->ref, ptr))
|
|
789
|
+
return;
|
|
790
|
+
} else if (IsNullOrUndefined(value)) {
|
|
791
|
+
ptr = nullptr;
|
|
792
|
+
} else {
|
|
793
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected %2", GetValueType(instance, value), type->name);
|
|
794
|
+
return;
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
out_reg->rax = (uint64_t)ptr;
|
|
798
|
+
} break;
|
|
799
|
+
case PrimitiveKind::Record: {
|
|
800
|
+
if (RG_UNLIKELY(!IsObject(value))) {
|
|
801
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected object", GetValueType(instance, value));
|
|
802
|
+
return;
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
Napi::Object obj = value.As<Napi::Object>();
|
|
806
|
+
|
|
807
|
+
if (return_ptr) {
|
|
808
|
+
if (!PushObject(obj, type, return_ptr))
|
|
809
|
+
return;
|
|
810
|
+
out_reg->rax = (uint64_t)return_ptr;
|
|
811
|
+
} else {
|
|
812
|
+
RG_ASSERT(type->size <= 16);
|
|
813
|
+
|
|
814
|
+
uint8_t buf[16] = {};
|
|
815
|
+
if (!PushObject(obj, type, buf))
|
|
816
|
+
return;
|
|
817
|
+
|
|
818
|
+
if (proto->ret.gpr_first && !proto->ret.xmm_count) {
|
|
819
|
+
memcpy(&out_reg->rax, buf + 0, 8);
|
|
820
|
+
memcpy(&out_reg->rdx, buf + 8, 8);
|
|
821
|
+
} else if (proto->ret.gpr_first) {
|
|
822
|
+
memcpy(&out_reg->rax, buf + 0, 8);
|
|
823
|
+
memcpy(&out_reg->xmm0, buf + 8, 8);
|
|
824
|
+
} else if (proto->ret.xmm_count == 2) {
|
|
825
|
+
memcpy(&out_reg->xmm0, buf + 0, 8);
|
|
826
|
+
memcpy(&out_reg->xmm1, buf + 8, 8);
|
|
827
|
+
} else {
|
|
828
|
+
memcpy(&out_reg->xmm0, buf + 0, 8);
|
|
829
|
+
memcpy(&out_reg->rax, buf + 8, 8);
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
} break;
|
|
833
|
+
case PrimitiveKind::Array: { RG_UNREACHABLE(); } break;
|
|
834
|
+
case PrimitiveKind::Float32: {
|
|
835
|
+
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
836
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected number", GetValueType(instance, value));
|
|
837
|
+
return;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
float f = CopyNumber<float>(value);
|
|
841
|
+
memcpy(&out_reg->xmm0, &f, 4);
|
|
842
|
+
} break;
|
|
843
|
+
case PrimitiveKind::Float64: {
|
|
844
|
+
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
845
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected number", GetValueType(instance, value));
|
|
846
|
+
return;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
double d = CopyNumber<double>(value);
|
|
850
|
+
out_reg->xmm0 = d;
|
|
851
|
+
} break;
|
|
852
|
+
case PrimitiveKind::Callback: {
|
|
853
|
+
void *ptr;
|
|
854
|
+
|
|
855
|
+
if (value.IsFunction()) {
|
|
856
|
+
Napi::Function func = value.As<Napi::Function>();
|
|
857
|
+
|
|
858
|
+
Size idx = ReserveTrampoline(type->proto, func);
|
|
859
|
+
if (RG_UNLIKELY(idx < 0))
|
|
860
|
+
return;
|
|
861
|
+
|
|
862
|
+
ptr = GetTrampoline(idx, type->proto);
|
|
863
|
+
} else if (CheckValueTag(instance, value, type)) {
|
|
864
|
+
ptr = value.As<Napi::External<uint8_t>>().Data();
|
|
865
|
+
} else if (IsNullOrUndefined(value)) {
|
|
866
|
+
ptr = nullptr;
|
|
867
|
+
} else {
|
|
868
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected %2", GetValueType(instance, value), type->name);
|
|
869
|
+
return;
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
out_reg->rax = (uint64_t)ptr;
|
|
873
|
+
} break;
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
void *GetTrampoline(Size idx, const FunctionInfo *proto)
|
|
878
|
+
{
|
|
879
|
+
bool xmm = proto->forward_fp || IsFloat(proto->ret.type);
|
|
880
|
+
return Trampolines[idx][xmm];
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
extern "C" void RelayCallBack(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
|
|
884
|
+
{
|
|
885
|
+
exec_call->Relay(idx, own_sp, caller_sp, out_reg);
|
|
886
|
+
}
|
|
887
|
+
|
|
516
888
|
}
|
|
517
889
|
|
|
518
890
|
#endif
|