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_arm32.cc
CHANGED
|
@@ -31,13 +31,65 @@ struct HfaRet {
|
|
|
31
31
|
double d3;
|
|
32
32
|
};
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
struct BackRegisters {
|
|
35
|
+
uint32_t r0;
|
|
36
|
+
uint32_t r1;
|
|
37
|
+
double d0;
|
|
38
|
+
double d1;
|
|
39
|
+
double d2;
|
|
40
|
+
double d3;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
extern "C" uint64_t ForwardCallGG(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
44
|
+
extern "C" float ForwardCallF(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
45
|
+
extern "C" HfaRet ForwardCallDDDD(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
46
|
+
|
|
47
|
+
extern "C" uint64_t ForwardCallXGG(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
48
|
+
extern "C" float ForwardCallXF(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
49
|
+
extern "C" HfaRet ForwardCallXDDDD(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
50
|
+
|
|
51
|
+
extern "C" int Trampoline0; extern "C" int TrampolineX0;
|
|
52
|
+
extern "C" int Trampoline1; extern "C" int TrampolineX1;
|
|
53
|
+
extern "C" int Trampoline2; extern "C" int TrampolineX2;
|
|
54
|
+
extern "C" int Trampoline3; extern "C" int TrampolineX3;
|
|
55
|
+
extern "C" int Trampoline4; extern "C" int TrampolineX4;
|
|
56
|
+
extern "C" int Trampoline5; extern "C" int TrampolineX5;
|
|
57
|
+
extern "C" int Trampoline6; extern "C" int TrampolineX6;
|
|
58
|
+
extern "C" int Trampoline7; extern "C" int TrampolineX7;
|
|
59
|
+
extern "C" int Trampoline8; extern "C" int TrampolineX8;
|
|
60
|
+
extern "C" int Trampoline9; extern "C" int TrampolineX9;
|
|
61
|
+
extern "C" int Trampoline10; extern "C" int TrampolineX10;
|
|
62
|
+
extern "C" int Trampoline11; extern "C" int TrampolineX11;
|
|
63
|
+
extern "C" int Trampoline12; extern "C" int TrampolineX12;
|
|
64
|
+
extern "C" int Trampoline13; extern "C" int TrampolineX13;
|
|
65
|
+
extern "C" int Trampoline14; extern "C" int TrampolineX14;
|
|
66
|
+
extern "C" int Trampoline15; extern "C" int TrampolineX15;
|
|
67
|
+
|
|
68
|
+
extern "C" napi_value CallSwitchStack(Napi::Function *func, size_t argc, napi_value *argv,
|
|
69
|
+
uint8_t *old_sp, Span<uint8_t> *new_stack,
|
|
70
|
+
napi_value (*call)(Napi::Function *func, size_t argc, napi_value *argv));
|
|
71
|
+
|
|
72
|
+
static void *const Trampolines[][2] = {
|
|
73
|
+
{ &Trampoline0, &TrampolineX0 },
|
|
74
|
+
{ &Trampoline1, &TrampolineX1 },
|
|
75
|
+
{ &Trampoline2, &TrampolineX2 },
|
|
76
|
+
{ &Trampoline3, &TrampolineX3 },
|
|
77
|
+
{ &Trampoline4, &TrampolineX4 },
|
|
78
|
+
{ &Trampoline5, &TrampolineX5 },
|
|
79
|
+
{ &Trampoline6, &TrampolineX6 },
|
|
80
|
+
{ &Trampoline7, &TrampolineX7 },
|
|
81
|
+
{ &Trampoline8, &TrampolineX8 },
|
|
82
|
+
{ &Trampoline9, &TrampolineX9 },
|
|
83
|
+
{ &Trampoline10, &TrampolineX10 },
|
|
84
|
+
{ &Trampoline11, &TrampolineX11 },
|
|
85
|
+
{ &Trampoline12, &TrampolineX12 },
|
|
86
|
+
{ &Trampoline13, &TrampolineX13 },
|
|
87
|
+
{ &Trampoline14, &TrampolineX14 },
|
|
88
|
+
{ &Trampoline15, &TrampolineX15 }
|
|
89
|
+
};
|
|
90
|
+
RG_STATIC_ASSERT(RG_LEN(Trampolines) == MaxTrampolines);
|
|
37
91
|
|
|
38
|
-
|
|
39
|
-
extern "C" float ForwardCallXF(const void *func, uint8_t *sp);
|
|
40
|
-
extern "C" HfaRet ForwardCallXDDDD(const void *func, uint8_t *sp);
|
|
92
|
+
static RG_THREAD_LOCAL CallData *exec_call;
|
|
41
93
|
|
|
42
94
|
static inline int IsHFA(const TypeInfo *type)
|
|
43
95
|
{
|
|
@@ -76,7 +128,8 @@ bool AnalyseFunction(InstanceData *, FunctionInfo *func)
|
|
|
76
128
|
case PrimitiveKind::UInt32:
|
|
77
129
|
case PrimitiveKind::String:
|
|
78
130
|
case PrimitiveKind::String16:
|
|
79
|
-
case PrimitiveKind::Pointer:
|
|
131
|
+
case PrimitiveKind::Pointer:
|
|
132
|
+
case PrimitiveKind::Callback: {
|
|
80
133
|
if (gpr_avail) {
|
|
81
134
|
param.gpr_count = 1;
|
|
82
135
|
gpr_avail--;
|
|
@@ -86,9 +139,11 @@ bool AnalyseFunction(InstanceData *, FunctionInfo *func)
|
|
|
86
139
|
} break;
|
|
87
140
|
case PrimitiveKind::Int64:
|
|
88
141
|
case PrimitiveKind::UInt64: {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
142
|
+
int need = 2 + (gpr_avail % 2);
|
|
143
|
+
|
|
144
|
+
if (gpr_avail >= need) {
|
|
145
|
+
param.gpr_count = need;
|
|
146
|
+
gpr_avail -= need;
|
|
92
147
|
} else {
|
|
93
148
|
started_stack = true;
|
|
94
149
|
}
|
|
@@ -127,7 +182,7 @@ bool AnalyseFunction(InstanceData *, FunctionInfo *func)
|
|
|
127
182
|
bool vfp = false;
|
|
128
183
|
#endif
|
|
129
184
|
|
|
130
|
-
|
|
185
|
+
int need = param.type->size / 4;
|
|
131
186
|
|
|
132
187
|
if (vfp) {
|
|
133
188
|
if (need <= vec_avail) {
|
|
@@ -137,6 +192,8 @@ bool AnalyseFunction(InstanceData *, FunctionInfo *func)
|
|
|
137
192
|
started_stack = true;
|
|
138
193
|
}
|
|
139
194
|
} else {
|
|
195
|
+
need += (gpr_avail % 2);
|
|
196
|
+
|
|
140
197
|
if (need <= gpr_avail) {
|
|
141
198
|
param.gpr_count = need;
|
|
142
199
|
gpr_avail -= need;
|
|
@@ -206,24 +263,37 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
206
263
|
case PrimitiveKind::UInt8:
|
|
207
264
|
case PrimitiveKind::Int16:
|
|
208
265
|
case PrimitiveKind::UInt16:
|
|
209
|
-
case PrimitiveKind::Int32:
|
|
266
|
+
case PrimitiveKind::Int32: {
|
|
267
|
+
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
268
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
|
|
269
|
+
return false;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
int32_t v = CopyNumber<int32_t>(value);
|
|
273
|
+
|
|
274
|
+
if (RG_LIKELY(param.gpr_count)) {
|
|
275
|
+
*(int32_t *)(gpr_ptr++) = v;
|
|
276
|
+
} else {
|
|
277
|
+
*(int32_t *)args_ptr = v;
|
|
278
|
+
args_ptr += 4;
|
|
279
|
+
}
|
|
280
|
+
} break;
|
|
210
281
|
case PrimitiveKind::UInt32: {
|
|
211
282
|
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
212
283
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
|
|
213
284
|
return false;
|
|
214
285
|
}
|
|
215
286
|
|
|
216
|
-
|
|
287
|
+
uint32_t v = CopyNumber<uint32_t>(value);
|
|
217
288
|
|
|
218
289
|
if (RG_LIKELY(param.gpr_count)) {
|
|
219
|
-
*(gpr_ptr++) =
|
|
290
|
+
*(gpr_ptr++) = v;
|
|
220
291
|
} else {
|
|
221
|
-
|
|
292
|
+
*(uint32_t *)args_ptr = v;
|
|
222
293
|
args_ptr += 4;
|
|
223
294
|
}
|
|
224
295
|
} break;
|
|
225
|
-
case PrimitiveKind::Int64:
|
|
226
|
-
case PrimitiveKind::UInt64: {
|
|
296
|
+
case PrimitiveKind::Int64: {
|
|
227
297
|
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
228
298
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
|
|
229
299
|
return false;
|
|
@@ -232,11 +302,30 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
232
302
|
int64_t v = CopyNumber<int64_t>(value);
|
|
233
303
|
|
|
234
304
|
if (RG_LIKELY(param.gpr_count)) {
|
|
235
|
-
|
|
236
|
-
gpr_ptr
|
|
305
|
+
gpr_ptr += param.gpr_count - 2;
|
|
306
|
+
*(int64_t *)gpr_ptr = v;
|
|
307
|
+
gpr_ptr += param.gpr_count;
|
|
237
308
|
} else {
|
|
238
309
|
args_ptr = AlignUp(args_ptr, 8);
|
|
239
|
-
|
|
310
|
+
*(int64_t *)args_ptr = v;
|
|
311
|
+
args_ptr += 8;
|
|
312
|
+
}
|
|
313
|
+
} break;
|
|
314
|
+
case PrimitiveKind::UInt64: {
|
|
315
|
+
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
316
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
|
|
317
|
+
return false;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
uint64_t v = CopyNumber<uint64_t>(value);
|
|
321
|
+
|
|
322
|
+
if (RG_LIKELY(param.gpr_count)) {
|
|
323
|
+
gpr_ptr += param.gpr_count - 2;
|
|
324
|
+
*(uint64_t *)gpr_ptr = v;
|
|
325
|
+
gpr_ptr += param.gpr_count;
|
|
326
|
+
} else {
|
|
327
|
+
args_ptr = AlignUp(args_ptr, 8);
|
|
328
|
+
*(uint64_t *)args_ptr = v;
|
|
240
329
|
args_ptr += 8;
|
|
241
330
|
}
|
|
242
331
|
} break;
|
|
@@ -357,11 +446,11 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
357
446
|
float f = CopyNumber<float>(value);
|
|
358
447
|
|
|
359
448
|
if (RG_LIKELY(param.vec_count)) {
|
|
360
|
-
|
|
449
|
+
*(float *)(vec_ptr++) = f;
|
|
361
450
|
} else if (param.gpr_count) {
|
|
362
|
-
|
|
451
|
+
*(float *)(gpr_ptr++) = f;
|
|
363
452
|
} else {
|
|
364
|
-
|
|
453
|
+
*(float *)args_ptr = f;
|
|
365
454
|
args_ptr += 4;
|
|
366
455
|
}
|
|
367
456
|
} break;
|
|
@@ -374,31 +463,61 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
374
463
|
double d = CopyNumber<double>(value);
|
|
375
464
|
|
|
376
465
|
if (RG_LIKELY(param.vec_count)) {
|
|
377
|
-
|
|
466
|
+
*(double *)vec_ptr = d;
|
|
378
467
|
vec_ptr += 2;
|
|
379
468
|
} else if (param.gpr_count) {
|
|
380
|
-
|
|
469
|
+
gpr_ptr += (param.gpr_count - 2);
|
|
470
|
+
*(double *)gpr_ptr = d;
|
|
381
471
|
gpr_ptr += 2;
|
|
382
472
|
} else {
|
|
383
473
|
args_ptr = AlignUp(args_ptr, 8);
|
|
384
|
-
|
|
474
|
+
*(double *)args_ptr = d;
|
|
385
475
|
args_ptr += 8;
|
|
386
476
|
}
|
|
387
477
|
} break;
|
|
478
|
+
case PrimitiveKind::Callback: {
|
|
479
|
+
void *ptr;
|
|
480
|
+
|
|
481
|
+
if (value.IsFunction()) {
|
|
482
|
+
Napi::Function func = value.As<Napi::Function>();
|
|
483
|
+
|
|
484
|
+
Size idx = ReserveTrampoline(param.type->proto, func);
|
|
485
|
+
if (RG_UNLIKELY(idx < 0))
|
|
486
|
+
return false;
|
|
487
|
+
|
|
488
|
+
ptr = GetTrampoline(idx, param.type->proto);
|
|
489
|
+
} else if (CheckValueTag(instance, value, param.type)) {
|
|
490
|
+
ptr = value.As<Napi::External<void>>().Data();
|
|
491
|
+
} else if (IsNullOrUndefined(value)) {
|
|
492
|
+
ptr = nullptr;
|
|
493
|
+
} else {
|
|
494
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected %3", GetValueType(instance, value), i + 1, param.type->name);
|
|
495
|
+
return false;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
if (RG_LIKELY(param.gpr_count)) {
|
|
499
|
+
*(gpr_ptr++) = (uint32_t)ptr;
|
|
500
|
+
} else {
|
|
501
|
+
*(void **)args_ptr = ptr;
|
|
502
|
+
args_ptr += 4;
|
|
503
|
+
}
|
|
504
|
+
} break;
|
|
388
505
|
}
|
|
389
506
|
}
|
|
390
507
|
|
|
391
|
-
|
|
508
|
+
new_sp = mem->stack.end();
|
|
392
509
|
|
|
393
510
|
return true;
|
|
394
511
|
}
|
|
395
512
|
|
|
396
513
|
void CallData::Execute()
|
|
397
514
|
{
|
|
515
|
+
exec_call = this;
|
|
516
|
+
|
|
398
517
|
#define PERFORM_CALL(Suffix) \
|
|
399
518
|
([&]() { \
|
|
400
|
-
auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func,
|
|
401
|
-
: ForwardCall ## Suffix(func->func,
|
|
519
|
+
auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, new_sp, &old_sp) \
|
|
520
|
+
: ForwardCall ## Suffix(func->func, new_sp, &old_sp)); \
|
|
402
521
|
return ret; \
|
|
403
522
|
})()
|
|
404
523
|
|
|
@@ -416,7 +535,8 @@ void CallData::Execute()
|
|
|
416
535
|
case PrimitiveKind::UInt64:
|
|
417
536
|
case PrimitiveKind::String:
|
|
418
537
|
case PrimitiveKind::String16:
|
|
419
|
-
case PrimitiveKind::Pointer:
|
|
538
|
+
case PrimitiveKind::Pointer:
|
|
539
|
+
case PrimitiveKind::Callback: { result.u64 = PERFORM_CALL(GG); } break;
|
|
420
540
|
case PrimitiveKind::Record: {
|
|
421
541
|
if (func->ret.vec_count) {
|
|
422
542
|
HfaRet ret = PERFORM_CALL(DDDD);
|
|
@@ -453,11 +573,16 @@ Napi::Value CallData::Complete()
|
|
|
453
573
|
case PrimitiveKind::UInt64: return Napi::BigInt::New(env, result.u64);
|
|
454
574
|
case PrimitiveKind::String: return Napi::String::New(env, (const char *)result.ptr);
|
|
455
575
|
case PrimitiveKind::String16: return Napi::String::New(env, (const char16_t *)result.ptr);
|
|
456
|
-
case PrimitiveKind::Pointer:
|
|
457
|
-
|
|
458
|
-
|
|
576
|
+
case PrimitiveKind::Pointer:
|
|
577
|
+
case PrimitiveKind::Callback: {
|
|
578
|
+
if (result.ptr) {
|
|
579
|
+
Napi::External<void> external = Napi::External<void>::New(env, result.ptr);
|
|
580
|
+
SetValueTag(instance, external, func->ret.type);
|
|
459
581
|
|
|
460
|
-
|
|
582
|
+
return external;
|
|
583
|
+
} else {
|
|
584
|
+
return env.Null();
|
|
585
|
+
}
|
|
461
586
|
} break;
|
|
462
587
|
case PrimitiveKind::Record: {
|
|
463
588
|
const uint8_t *ptr = return_ptr ? (const uint8_t *)return_ptr
|
|
@@ -474,6 +599,367 @@ Napi::Value CallData::Complete()
|
|
|
474
599
|
RG_UNREACHABLE();
|
|
475
600
|
}
|
|
476
601
|
|
|
602
|
+
void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
|
|
603
|
+
{
|
|
604
|
+
const FunctionInfo *proto = instance->trampolines[idx].proto;
|
|
605
|
+
Napi::Function func = instance->trampolines[idx].func;
|
|
606
|
+
|
|
607
|
+
// Allow reuse of static trampoline
|
|
608
|
+
instance->free_trampolines |= 1u << idx;
|
|
609
|
+
used_trampolines &= ~(1u << idx);
|
|
610
|
+
|
|
611
|
+
uint64_t *vec_ptr = (uint64_t *)own_sp;
|
|
612
|
+
uint32_t *gpr_ptr = (uint32_t *)(vec_ptr + 8);
|
|
613
|
+
uint32_t *args_ptr = (uint32_t *)caller_sp;
|
|
614
|
+
|
|
615
|
+
uint8_t *return_ptr = proto->ret.use_memory ? (uint8_t *)gpr_ptr[0] : nullptr;
|
|
616
|
+
gpr_ptr += proto->ret.use_memory;
|
|
617
|
+
|
|
618
|
+
LocalArray<napi_value, MaxParameters> arguments;
|
|
619
|
+
|
|
620
|
+
// Convert to JS arguments
|
|
621
|
+
for (Size i = 0; i < proto->parameters.len; i++) {
|
|
622
|
+
const ParameterInfo ¶m = proto->parameters[i];
|
|
623
|
+
RG_ASSERT(param.directions >= 1 && param.directions <= 3);
|
|
624
|
+
|
|
625
|
+
switch (param.type->primitive) {
|
|
626
|
+
case PrimitiveKind::Void: { RG_UNREACHABLE(); } break;
|
|
627
|
+
|
|
628
|
+
case PrimitiveKind::Bool: {
|
|
629
|
+
bool b = *(bool *)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
630
|
+
|
|
631
|
+
Napi::Value arg = Napi::Boolean::New(env, b);
|
|
632
|
+
arguments.Append(arg);
|
|
633
|
+
} break;
|
|
634
|
+
case PrimitiveKind::Int8: {
|
|
635
|
+
double d = (double)*(int8_t *)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
636
|
+
|
|
637
|
+
Napi::Value arg = Napi::Number::New(env, d);
|
|
638
|
+
arguments.Append(arg);
|
|
639
|
+
} break;
|
|
640
|
+
case PrimitiveKind::UInt8: {
|
|
641
|
+
double d = (double)*(uint8_t *)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
642
|
+
|
|
643
|
+
Napi::Value arg = Napi::Number::New(env, d);
|
|
644
|
+
arguments.Append(arg);
|
|
645
|
+
} break;
|
|
646
|
+
case PrimitiveKind::Int16: {
|
|
647
|
+
double d = (double)*(int16_t *)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
648
|
+
|
|
649
|
+
Napi::Value arg = Napi::Number::New(env, d);
|
|
650
|
+
arguments.Append(arg);
|
|
651
|
+
} break;
|
|
652
|
+
case PrimitiveKind::UInt16: {
|
|
653
|
+
double d = (double)*(uint16_t *)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
654
|
+
|
|
655
|
+
Napi::Value arg = Napi::Number::New(env, d);
|
|
656
|
+
arguments.Append(arg);
|
|
657
|
+
} break;
|
|
658
|
+
case PrimitiveKind::Int32: {
|
|
659
|
+
double d = (double)*(int32_t *)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
660
|
+
|
|
661
|
+
Napi::Value arg = Napi::Number::New(env, d);
|
|
662
|
+
arguments.Append(arg);
|
|
663
|
+
} break;
|
|
664
|
+
case PrimitiveKind::UInt32: {
|
|
665
|
+
double d = (double)*(int32_t *)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
666
|
+
|
|
667
|
+
Napi::Value arg = Napi::Number::New(env, d);
|
|
668
|
+
arguments.Append(arg);
|
|
669
|
+
} break;
|
|
670
|
+
case PrimitiveKind::Int64: {
|
|
671
|
+
gpr_ptr += param.gpr_count - 2;
|
|
672
|
+
int64_t v = *(int64_t *)(param.gpr_count ? gpr_ptr : args_ptr);
|
|
673
|
+
(param.gpr_count ? gpr_ptr : args_ptr) += 2;
|
|
674
|
+
|
|
675
|
+
Napi::Value arg = Napi::BigInt::New(env, v);
|
|
676
|
+
arguments.Append(arg);
|
|
677
|
+
} break;
|
|
678
|
+
case PrimitiveKind::UInt64: {
|
|
679
|
+
gpr_ptr += param.gpr_count - 2;
|
|
680
|
+
uint64_t v = *(uint64_t *)(param.gpr_count ? gpr_ptr : args_ptr);
|
|
681
|
+
(param.gpr_count ? gpr_ptr : args_ptr) += 2;
|
|
682
|
+
|
|
683
|
+
Napi::Value arg = Napi::BigInt::New(env, v);
|
|
684
|
+
arguments.Append(arg);
|
|
685
|
+
} break;
|
|
686
|
+
case PrimitiveKind::String: {
|
|
687
|
+
const char *str = *(const char **)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
688
|
+
|
|
689
|
+
Napi::Value arg = Napi::String::New(env, str);
|
|
690
|
+
arguments.Append(arg);
|
|
691
|
+
} break;
|
|
692
|
+
case PrimitiveKind::String16: {
|
|
693
|
+
const char16_t *str16 = *(const char16_t **)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
694
|
+
|
|
695
|
+
Napi::Value arg = Napi::String::New(env, str16);
|
|
696
|
+
arguments.Append(arg);
|
|
697
|
+
} break;
|
|
698
|
+
case PrimitiveKind::Pointer:
|
|
699
|
+
case PrimitiveKind::Callback: {
|
|
700
|
+
void *ptr2 = *(void **)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
701
|
+
|
|
702
|
+
if (ptr2) {
|
|
703
|
+
Napi::External<void> external = Napi::External<void>::New(env, ptr2);
|
|
704
|
+
SetValueTag(instance, external, param.type);
|
|
705
|
+
|
|
706
|
+
arguments.Append(external);
|
|
707
|
+
} else {
|
|
708
|
+
arguments.Append(env.Null());
|
|
709
|
+
}
|
|
710
|
+
} break;
|
|
711
|
+
case PrimitiveKind::Record: {
|
|
712
|
+
if (param.vec_count) {
|
|
713
|
+
Napi::Object obj = PopObject((const uint8_t *)vec_ptr, param.type);
|
|
714
|
+
arguments.Append(obj);
|
|
715
|
+
|
|
716
|
+
vec_ptr += param.vec_count;
|
|
717
|
+
} else if (param.gpr_count) {
|
|
718
|
+
RG_ASSERT(param.type->align <= 8);
|
|
719
|
+
|
|
720
|
+
Napi::Object obj = PopObject((const uint8_t *)gpr_ptr, param.type);
|
|
721
|
+
arguments.Append(obj);
|
|
722
|
+
|
|
723
|
+
gpr_ptr += param.gpr_count;
|
|
724
|
+
args_ptr += (param.type->size - param.gpr_count * 4 + 3) / 4;
|
|
725
|
+
} else if (param.type->size) {
|
|
726
|
+
int16_t align = (param.type->align <= 4) ? 4 : 8;
|
|
727
|
+
args_ptr = AlignUp(args_ptr, align);
|
|
728
|
+
|
|
729
|
+
Napi::Object obj = PopObject((const uint8_t *)args_ptr, param.type);
|
|
730
|
+
arguments.Append(obj);
|
|
731
|
+
|
|
732
|
+
args_ptr += (param.type->size + 3) / 4;
|
|
733
|
+
}
|
|
734
|
+
} break;
|
|
735
|
+
case PrimitiveKind::Array: { RG_UNREACHABLE(); } break;
|
|
736
|
+
case PrimitiveKind::Float32: {
|
|
737
|
+
float f;
|
|
738
|
+
if (RG_LIKELY(param.vec_count)) {
|
|
739
|
+
f = *(float *)(vec_ptr++);
|
|
740
|
+
} else if (param.gpr_count) {
|
|
741
|
+
f = *(float *)(gpr_ptr++);
|
|
742
|
+
} else {
|
|
743
|
+
f = *(float *)(args_ptr++);
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
Napi::Value arg = Napi::Number::New(env, (double)f);
|
|
747
|
+
arguments.Append(arg);
|
|
748
|
+
} break;
|
|
749
|
+
case PrimitiveKind::Float64: {
|
|
750
|
+
double d;
|
|
751
|
+
if (RG_LIKELY(param.vec_count)) {
|
|
752
|
+
d = *(double *)vec_ptr;
|
|
753
|
+
vec_ptr += 2;
|
|
754
|
+
} else if (param.gpr_count) {
|
|
755
|
+
gpr_ptr += param.gpr_count - 2;
|
|
756
|
+
d = *(double *)gpr_ptr;
|
|
757
|
+
gpr_ptr += 2;
|
|
758
|
+
} else {
|
|
759
|
+
d = *(double *)args_ptr;
|
|
760
|
+
args_ptr += 2;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
Napi::Value arg = Napi::Number::New(env, d);
|
|
764
|
+
arguments.Append(arg);
|
|
765
|
+
} break;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
const TypeInfo *type = proto->ret.type;
|
|
770
|
+
|
|
771
|
+
// Make the call
|
|
772
|
+
napi_value ret = CallSwitchStack(&func, (size_t)arguments.len, arguments.data, old_sp, &mem->stack,
|
|
773
|
+
[](Napi::Function *func, size_t argc, napi_value *argv) { return (napi_value)func->Call(argc, argv); });
|
|
774
|
+
Napi::Value value(env, ret);
|
|
775
|
+
|
|
776
|
+
// Convert the result
|
|
777
|
+
switch (type->primitive) {
|
|
778
|
+
case PrimitiveKind::Void: {} break;
|
|
779
|
+
case PrimitiveKind::Bool: {
|
|
780
|
+
if (RG_UNLIKELY(!value.IsBoolean())) {
|
|
781
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected boolean", GetValueType(instance, value));
|
|
782
|
+
return;
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
bool b = value.As<Napi::Boolean>();
|
|
786
|
+
out_reg->r0 = (uint32_t)b;
|
|
787
|
+
} break;
|
|
788
|
+
case PrimitiveKind::Int8:
|
|
789
|
+
case PrimitiveKind::UInt8:
|
|
790
|
+
case PrimitiveKind::Int16:
|
|
791
|
+
case PrimitiveKind::UInt16:
|
|
792
|
+
case PrimitiveKind::Int32: {
|
|
793
|
+
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
794
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected number", GetValueType(instance, value));
|
|
795
|
+
return;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
int32_t v = CopyNumber<int32_t>(value);
|
|
799
|
+
out_reg->r0 = (uint32_t)v;
|
|
800
|
+
} break;
|
|
801
|
+
case PrimitiveKind::UInt32: {
|
|
802
|
+
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
803
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected number", GetValueType(instance, value));
|
|
804
|
+
return;
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
uint32_t v = CopyNumber<uint32_t>(value);
|
|
808
|
+
out_reg->r0 = v;
|
|
809
|
+
} break;
|
|
810
|
+
case PrimitiveKind::Int64: {
|
|
811
|
+
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
812
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected number", GetValueType(instance, value));
|
|
813
|
+
return;
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
int64_t v = CopyNumber<int64_t>(value);
|
|
817
|
+
out_reg->r0 = (uint32_t)(v >> 32);
|
|
818
|
+
out_reg->r1 = (uint32_t)((uint64_t)v & 0xFFFFFFFFu);
|
|
819
|
+
} break;
|
|
820
|
+
case PrimitiveKind::UInt64: {
|
|
821
|
+
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
822
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected number", GetValueType(instance, value));
|
|
823
|
+
return;
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
uint64_t v = CopyNumber<uint64_t>(value);
|
|
827
|
+
out_reg->r0 = (uint32_t)(v >> 32);
|
|
828
|
+
out_reg->r1 = (uint32_t)((uint64_t)v & 0xFFFFFFFFu);
|
|
829
|
+
} break;
|
|
830
|
+
case PrimitiveKind::String: {
|
|
831
|
+
const char *str;
|
|
832
|
+
if (RG_LIKELY(value.IsString())) {
|
|
833
|
+
str = PushString(value);
|
|
834
|
+
if (RG_UNLIKELY(!str))
|
|
835
|
+
return;
|
|
836
|
+
} else if (IsNullOrUndefined(value)) {
|
|
837
|
+
str = nullptr;
|
|
838
|
+
} else {
|
|
839
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected string", GetValueType(instance, value));
|
|
840
|
+
return;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
out_reg->r0 = (uint32_t)str;
|
|
844
|
+
} break;
|
|
845
|
+
case PrimitiveKind::String16: {
|
|
846
|
+
const char16_t *str16;
|
|
847
|
+
if (RG_LIKELY(value.IsString())) {
|
|
848
|
+
str16 = PushString16(value);
|
|
849
|
+
if (RG_UNLIKELY(!str16))
|
|
850
|
+
return;
|
|
851
|
+
} else if (IsNullOrUndefined(value)) {
|
|
852
|
+
str16 = nullptr;
|
|
853
|
+
} else {
|
|
854
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected string", GetValueType(instance, value));
|
|
855
|
+
return;
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
out_reg->r0 = (uint32_t)str16;
|
|
859
|
+
} break;
|
|
860
|
+
case PrimitiveKind::Pointer: {
|
|
861
|
+
uint8_t *ptr;
|
|
862
|
+
|
|
863
|
+
if (CheckValueTag(instance, value, type)) {
|
|
864
|
+
ptr = value.As<Napi::External<uint8_t>>().Data();
|
|
865
|
+
} else if (IsObject(value) && type->ref->primitive == PrimitiveKind::Record) {
|
|
866
|
+
Napi::Object obj = value.As<Napi::Object>();
|
|
867
|
+
|
|
868
|
+
if (RG_UNLIKELY(!AllocHeap(type->ref->size, 16, &ptr)))
|
|
869
|
+
return;
|
|
870
|
+
|
|
871
|
+
if (!PushObject(obj, type->ref, ptr))
|
|
872
|
+
return;
|
|
873
|
+
} else if (IsNullOrUndefined(value)) {
|
|
874
|
+
ptr = nullptr;
|
|
875
|
+
} else {
|
|
876
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected %2", GetValueType(instance, value), type->name);
|
|
877
|
+
return;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
out_reg->r0 = (uint32_t)ptr;
|
|
881
|
+
} break;
|
|
882
|
+
case PrimitiveKind::Record: {
|
|
883
|
+
if (RG_UNLIKELY(!IsObject(value))) {
|
|
884
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected object", GetValueType(instance, value));
|
|
885
|
+
return;
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
Napi::Object obj = value.As<Napi::Object>();
|
|
889
|
+
|
|
890
|
+
if (return_ptr) {
|
|
891
|
+
if (!PushObject(obj, type, return_ptr))
|
|
892
|
+
return;
|
|
893
|
+
out_reg->r0 = (uint32_t)return_ptr;
|
|
894
|
+
} else if (proto->ret.vec_count) { // HFA
|
|
895
|
+
PushObject(obj, type, (uint8_t *)&out_reg->d0, 8);
|
|
896
|
+
} else {
|
|
897
|
+
PushObject(obj, type, (uint8_t *)&out_reg->r0);
|
|
898
|
+
}
|
|
899
|
+
} break;
|
|
900
|
+
case PrimitiveKind::Array: { RG_UNREACHABLE(); } break;
|
|
901
|
+
case PrimitiveKind::Float32: {
|
|
902
|
+
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
903
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected number", GetValueType(instance, value));
|
|
904
|
+
return;
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
float f = CopyNumber<float>(value);
|
|
908
|
+
#ifdef __ARM_PCS_VFP
|
|
909
|
+
memcpy(&out_reg->d0, &f, 4);
|
|
910
|
+
#else
|
|
911
|
+
memcpy(&out_reg->r0, &f, 4);
|
|
912
|
+
#endif
|
|
913
|
+
} break;
|
|
914
|
+
case PrimitiveKind::Float64: {
|
|
915
|
+
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
916
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected number", GetValueType(instance, value));
|
|
917
|
+
return;
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
double d = CopyNumber<double>(value);
|
|
921
|
+
#ifdef __ARM_PCS_VFP
|
|
922
|
+
out_reg->d0 = d;
|
|
923
|
+
#else
|
|
924
|
+
memcpy(&out_reg->r0, &d, 8);
|
|
925
|
+
#endif
|
|
926
|
+
} break;
|
|
927
|
+
case PrimitiveKind::Callback: {
|
|
928
|
+
void *ptr;
|
|
929
|
+
|
|
930
|
+
if (value.IsFunction()) {
|
|
931
|
+
Napi::Function func = value.As<Napi::Function>();
|
|
932
|
+
|
|
933
|
+
Size idx = ReserveTrampoline(type->proto, func);
|
|
934
|
+
if (RG_UNLIKELY(idx < 0))
|
|
935
|
+
return;
|
|
936
|
+
|
|
937
|
+
ptr = GetTrampoline(idx, type->proto);
|
|
938
|
+
} else if (CheckValueTag(instance, value, type)) {
|
|
939
|
+
ptr = value.As<Napi::External<uint8_t>>().Data();
|
|
940
|
+
} else if (IsNullOrUndefined(value)) {
|
|
941
|
+
ptr = nullptr;
|
|
942
|
+
} else {
|
|
943
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected %2", GetValueType(instance, value), type->name);
|
|
944
|
+
return;
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
out_reg->r0 = (uint32_t)ptr;
|
|
948
|
+
} break;
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
void *GetTrampoline(Size idx, const FunctionInfo *proto)
|
|
953
|
+
{
|
|
954
|
+
bool vec = proto->forward_fp || IsFloat(proto->ret.type);
|
|
955
|
+
return Trampolines[idx][vec];
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
extern "C" void RelayCallBack(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
|
|
959
|
+
{
|
|
960
|
+
exec_call->Relay(idx, own_sp, caller_sp, out_reg);
|
|
961
|
+
}
|
|
962
|
+
|
|
477
963
|
}
|
|
478
964
|
|
|
479
965
|
#endif
|