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_riscv64.cc
CHANGED
|
@@ -39,17 +39,67 @@ struct Fa0Fa1Ret {
|
|
|
39
39
|
double fa1;
|
|
40
40
|
};
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
extern "C"
|
|
50
|
-
extern "C"
|
|
51
|
-
extern "C"
|
|
52
|
-
extern "C"
|
|
42
|
+
struct BackRegisters {
|
|
43
|
+
uint64_t a0;
|
|
44
|
+
uint64_t a1;
|
|
45
|
+
double fa0;
|
|
46
|
+
double fa1;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
extern "C" A0A1Ret ForwardCallGG(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
50
|
+
extern "C" float ForwardCallF(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
51
|
+
extern "C" Fa0A0Ret ForwardCallDG(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
52
|
+
extern "C" A0Fa0Ret ForwardCallGD(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
53
|
+
extern "C" Fa0Fa1Ret ForwardCallDD(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
54
|
+
|
|
55
|
+
extern "C" A0A1Ret ForwardCallXGG(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
56
|
+
extern "C" float ForwardCallXF(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
57
|
+
extern "C" Fa0A0Ret ForwardCallXDG(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
58
|
+
extern "C" A0Fa0Ret ForwardCallXGD(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
59
|
+
extern "C" Fa0Fa1Ret ForwardCallXDD(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
60
|
+
|
|
61
|
+
extern "C" int Trampoline0; extern "C" int TrampolineX0;
|
|
62
|
+
extern "C" int Trampoline1; extern "C" int TrampolineX1;
|
|
63
|
+
extern "C" int Trampoline2; extern "C" int TrampolineX2;
|
|
64
|
+
extern "C" int Trampoline3; extern "C" int TrampolineX3;
|
|
65
|
+
extern "C" int Trampoline4; extern "C" int TrampolineX4;
|
|
66
|
+
extern "C" int Trampoline5; extern "C" int TrampolineX5;
|
|
67
|
+
extern "C" int Trampoline6; extern "C" int TrampolineX6;
|
|
68
|
+
extern "C" int Trampoline7; extern "C" int TrampolineX7;
|
|
69
|
+
extern "C" int Trampoline8; extern "C" int TrampolineX8;
|
|
70
|
+
extern "C" int Trampoline9; extern "C" int TrampolineX9;
|
|
71
|
+
extern "C" int Trampoline10; extern "C" int TrampolineX10;
|
|
72
|
+
extern "C" int Trampoline11; extern "C" int TrampolineX11;
|
|
73
|
+
extern "C" int Trampoline12; extern "C" int TrampolineX12;
|
|
74
|
+
extern "C" int Trampoline13; extern "C" int TrampolineX13;
|
|
75
|
+
extern "C" int Trampoline14; extern "C" int TrampolineX14;
|
|
76
|
+
extern "C" int Trampoline15; extern "C" int TrampolineX15;
|
|
77
|
+
|
|
78
|
+
extern "C" napi_value CallSwitchStack(Napi::Function *func, size_t argc, napi_value *argv,
|
|
79
|
+
uint8_t *old_sp, Span<uint8_t> *new_stack,
|
|
80
|
+
napi_value (*call)(Napi::Function *func, size_t argc, napi_value *argv));
|
|
81
|
+
|
|
82
|
+
static void *const Trampolines[][2] = {
|
|
83
|
+
{ &Trampoline0, &TrampolineX0 },
|
|
84
|
+
{ &Trampoline1, &TrampolineX1 },
|
|
85
|
+
{ &Trampoline2, &TrampolineX2 },
|
|
86
|
+
{ &Trampoline3, &TrampolineX3 },
|
|
87
|
+
{ &Trampoline4, &TrampolineX4 },
|
|
88
|
+
{ &Trampoline5, &TrampolineX5 },
|
|
89
|
+
{ &Trampoline6, &TrampolineX6 },
|
|
90
|
+
{ &Trampoline7, &TrampolineX7 },
|
|
91
|
+
{ &Trampoline8, &TrampolineX8 },
|
|
92
|
+
{ &Trampoline9, &TrampolineX9 },
|
|
93
|
+
{ &Trampoline10, &TrampolineX10 },
|
|
94
|
+
{ &Trampoline11, &TrampolineX11 },
|
|
95
|
+
{ &Trampoline12, &TrampolineX12 },
|
|
96
|
+
{ &Trampoline13, &TrampolineX13 },
|
|
97
|
+
{ &Trampoline14, &TrampolineX14 },
|
|
98
|
+
{ &Trampoline15, &TrampolineX15 }
|
|
99
|
+
};
|
|
100
|
+
RG_STATIC_ASSERT(RG_LEN(Trampolines) == MaxTrampolines);
|
|
101
|
+
|
|
102
|
+
static RG_THREAD_LOCAL CallData *exec_call;
|
|
53
103
|
|
|
54
104
|
static void AnalyseParameter(ParameterInfo *param, int gpr_avail, int vec_avail)
|
|
55
105
|
{
|
|
@@ -118,7 +168,7 @@ bool AnalyseFunction(InstanceData *, FunctionInfo *func)
|
|
|
118
168
|
|
|
119
169
|
bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
120
170
|
{
|
|
121
|
-
|
|
171
|
+
uint64_t *args_ptr = nullptr;
|
|
122
172
|
uint64_t *gpr_ptr = nullptr;
|
|
123
173
|
uint64_t *vec_ptr = nullptr;
|
|
124
174
|
|
|
@@ -152,13 +202,7 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
152
202
|
}
|
|
153
203
|
|
|
154
204
|
bool b = value.As<Napi::Boolean>();
|
|
155
|
-
|
|
156
|
-
if (RG_LIKELY(param.gpr_count)) {
|
|
157
|
-
*(gpr_ptr++) = (uint64_t)b;
|
|
158
|
-
} else {
|
|
159
|
-
*(uint64_t *)args_ptr = (uint64_t)b;
|
|
160
|
-
args_ptr += 8;
|
|
161
|
-
}
|
|
205
|
+
*((param.gpr_count ? gpr_ptr : args_ptr)++) = (uint64_t)b;
|
|
162
206
|
} break;
|
|
163
207
|
case PrimitiveKind::Int8:
|
|
164
208
|
case PrimitiveKind::Int16:
|
|
@@ -170,13 +214,7 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
170
214
|
}
|
|
171
215
|
|
|
172
216
|
int64_t v = CopyNumber<int64_t>(value);
|
|
173
|
-
|
|
174
|
-
if (RG_LIKELY(param.gpr_count)) {
|
|
175
|
-
*(int64_t *)(gpr_ptr++) = v;
|
|
176
|
-
} else {
|
|
177
|
-
*(int64_t *)args_ptr = v;
|
|
178
|
-
args_ptr += 8;
|
|
179
|
-
}
|
|
217
|
+
*(int64_t *)((param.gpr_count ? gpr_ptr : args_ptr)++) = v;
|
|
180
218
|
} break;
|
|
181
219
|
case PrimitiveKind::UInt8:
|
|
182
220
|
case PrimitiveKind::UInt16:
|
|
@@ -188,13 +226,7 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
188
226
|
}
|
|
189
227
|
|
|
190
228
|
uint64_t v = CopyNumber<uint64_t>(value);
|
|
191
|
-
|
|
192
|
-
if (RG_LIKELY(param.gpr_count)) {
|
|
193
|
-
*(uint64_t *)(gpr_ptr++) = v;
|
|
194
|
-
} else {
|
|
195
|
-
*(uint64_t *)args_ptr = v;
|
|
196
|
-
args_ptr += 8;
|
|
197
|
-
}
|
|
229
|
+
*((param.gpr_count ? gpr_ptr : args_ptr)++) = v;
|
|
198
230
|
} break;
|
|
199
231
|
case PrimitiveKind::String: {
|
|
200
232
|
const char *str;
|
|
@@ -209,12 +241,7 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
209
241
|
return false;
|
|
210
242
|
}
|
|
211
243
|
|
|
212
|
-
|
|
213
|
-
*(const char **)(gpr_ptr++) = str;
|
|
214
|
-
} else {
|
|
215
|
-
*(const char **)args_ptr = str;
|
|
216
|
-
args_ptr += 8;
|
|
217
|
-
}
|
|
244
|
+
*(const char **)((param.gpr_count ? gpr_ptr : args_ptr)++) = str;
|
|
218
245
|
} break;
|
|
219
246
|
case PrimitiveKind::String16: {
|
|
220
247
|
const char16_t *str16;
|
|
@@ -229,12 +256,7 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
229
256
|
return false;
|
|
230
257
|
}
|
|
231
258
|
|
|
232
|
-
|
|
233
|
-
*(const char16_t **)(gpr_ptr++) = str16;
|
|
234
|
-
} else {
|
|
235
|
-
*(const char16_t **)args_ptr = str16;
|
|
236
|
-
args_ptr += 8;
|
|
237
|
-
}
|
|
259
|
+
*(const char16_t **)((param.gpr_count ? gpr_ptr : args_ptr)++) = str16;
|
|
238
260
|
} break;
|
|
239
261
|
case PrimitiveKind::Pointer: {
|
|
240
262
|
uint8_t *ptr;
|
|
@@ -267,12 +289,7 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
267
289
|
return false;
|
|
268
290
|
}
|
|
269
291
|
|
|
270
|
-
|
|
271
|
-
*(uint8_t **)(gpr_ptr++) = ptr;
|
|
272
|
-
} else {
|
|
273
|
-
*(uint8_t **)args_ptr = ptr;
|
|
274
|
-
args_ptr += 8;
|
|
275
|
-
}
|
|
292
|
+
*(uint8_t **)((param.gpr_count ? gpr_ptr : args_ptr)++) = ptr;
|
|
276
293
|
} break;
|
|
277
294
|
case PrimitiveKind::Record: {
|
|
278
295
|
if (RG_UNLIKELY(!IsObject(value))) {
|
|
@@ -304,7 +321,7 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
304
321
|
RG_ASSERT(param.type->align <= 8);
|
|
305
322
|
|
|
306
323
|
memcpy_safe(args_ptr, ptr, param.type->size);
|
|
307
|
-
args_ptr +=
|
|
324
|
+
args_ptr += (param.type->size + 7) / 8;
|
|
308
325
|
}
|
|
309
326
|
} else {
|
|
310
327
|
uint8_t *ptr;
|
|
@@ -317,8 +334,7 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
317
334
|
|
|
318
335
|
*(uint8_t **)(gpr_ptr++) = ptr;
|
|
319
336
|
} else {
|
|
320
|
-
*(uint8_t **)args_ptr = ptr;
|
|
321
|
-
args_ptr += 8;
|
|
337
|
+
*(uint8_t **)(args_ptr++) = ptr;
|
|
322
338
|
}
|
|
323
339
|
|
|
324
340
|
if (!PushObject(obj, param.type, ptr))
|
|
@@ -341,8 +357,8 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
341
357
|
memset((uint8_t *)gpr_ptr + 4, 0xFF, 4);
|
|
342
358
|
*(float *)(gpr_ptr++) = f;
|
|
343
359
|
} else {
|
|
344
|
-
memset(args_ptr
|
|
345
|
-
*(float *)args_ptr = f;
|
|
360
|
+
memset(args_ptr, 0xFF, 8);
|
|
361
|
+
*(float *)(args_ptr++) = f;
|
|
346
362
|
}
|
|
347
363
|
} break;
|
|
348
364
|
case PrimitiveKind::Float64: {
|
|
@@ -358,24 +374,47 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
|
|
|
358
374
|
} else if (param.gpr_count) {
|
|
359
375
|
*(double *)(gpr_ptr++) = d;
|
|
360
376
|
} else {
|
|
361
|
-
*(double *)args_ptr = d;
|
|
362
|
-
args_ptr += 8;
|
|
377
|
+
*(double *)(args_ptr++) = d;
|
|
363
378
|
}
|
|
364
379
|
} break;
|
|
380
|
+
case PrimitiveKind::Callback: {
|
|
381
|
+
void *ptr;
|
|
382
|
+
|
|
383
|
+
if (value.IsFunction()) {
|
|
384
|
+
Napi::Function func = value.As<Napi::Function>();
|
|
385
|
+
|
|
386
|
+
Size idx = ReserveTrampoline(param.type->proto, func);
|
|
387
|
+
if (RG_UNLIKELY(idx < 0))
|
|
388
|
+
return false;
|
|
389
|
+
|
|
390
|
+
ptr = GetTrampoline(idx, param.type->proto);
|
|
391
|
+
} else if (CheckValueTag(instance, value, param.type)) {
|
|
392
|
+
ptr = value.As<Napi::External<void>>().Data();
|
|
393
|
+
} else if (IsNullOrUndefined(value)) {
|
|
394
|
+
ptr = nullptr;
|
|
395
|
+
} else {
|
|
396
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected %3", GetValueType(instance, value), i + 1, param.type->name);
|
|
397
|
+
return false;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
*(void **)((param.gpr_count ? gpr_ptr : args_ptr)++) = ptr;
|
|
401
|
+
} break;
|
|
365
402
|
}
|
|
366
403
|
}
|
|
367
404
|
|
|
368
|
-
|
|
405
|
+
new_sp = mem->stack.end();
|
|
369
406
|
|
|
370
407
|
return true;
|
|
371
408
|
}
|
|
372
409
|
|
|
373
410
|
void CallData::Execute()
|
|
374
411
|
{
|
|
412
|
+
exec_call = this;
|
|
413
|
+
|
|
375
414
|
#define PERFORM_CALL(Suffix) \
|
|
376
415
|
([&]() { \
|
|
377
|
-
auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func,
|
|
378
|
-
: ForwardCall ## Suffix(func->func,
|
|
416
|
+
auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, new_sp, &old_sp) \
|
|
417
|
+
: ForwardCall ## Suffix(func->func, new_sp, &old_sp)); \
|
|
379
418
|
return ret; \
|
|
380
419
|
})()
|
|
381
420
|
|
|
@@ -393,7 +432,8 @@ void CallData::Execute()
|
|
|
393
432
|
case PrimitiveKind::UInt64:
|
|
394
433
|
case PrimitiveKind::String:
|
|
395
434
|
case PrimitiveKind::String16:
|
|
396
|
-
case PrimitiveKind::Pointer:
|
|
435
|
+
case PrimitiveKind::Pointer:
|
|
436
|
+
case PrimitiveKind::Callback: { result.u64 = PERFORM_CALL(GG).a0; } break;
|
|
397
437
|
case PrimitiveKind::Record: {
|
|
398
438
|
if (func->ret.gpr_first && !func->ret.vec_count) {
|
|
399
439
|
A0A1Ret ret = PERFORM_CALL(GG);
|
|
@@ -437,11 +477,16 @@ Napi::Value CallData::Complete()
|
|
|
437
477
|
case PrimitiveKind::UInt64: return Napi::BigInt::New(env, result.u64);
|
|
438
478
|
case PrimitiveKind::String: return Napi::String::New(env, (const char *)result.ptr);
|
|
439
479
|
case PrimitiveKind::String16: return Napi::String::New(env, (const char16_t *)result.ptr);
|
|
440
|
-
case PrimitiveKind::Pointer:
|
|
441
|
-
|
|
442
|
-
|
|
480
|
+
case PrimitiveKind::Pointer:
|
|
481
|
+
case PrimitiveKind::Callback: {
|
|
482
|
+
if (result.ptr) {
|
|
483
|
+
Napi::External<void> external = Napi::External<void>::New(env, result.ptr);
|
|
484
|
+
SetValueTag(instance, external, func->ret.type);
|
|
443
485
|
|
|
444
|
-
|
|
486
|
+
return external;
|
|
487
|
+
} else {
|
|
488
|
+
return env.Null();
|
|
489
|
+
}
|
|
445
490
|
} break;
|
|
446
491
|
case PrimitiveKind::Record: {
|
|
447
492
|
if (func->ret.vec_count) { // HFA
|
|
@@ -463,6 +508,333 @@ Napi::Value CallData::Complete()
|
|
|
463
508
|
RG_UNREACHABLE();
|
|
464
509
|
}
|
|
465
510
|
|
|
511
|
+
void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
|
|
512
|
+
{
|
|
513
|
+
const FunctionInfo *proto = instance->trampolines[idx].proto;
|
|
514
|
+
Napi::Function func = instance->trampolines[idx].func;
|
|
515
|
+
|
|
516
|
+
// Allow reuse of static trampoline
|
|
517
|
+
instance->free_trampolines |= 1u << idx;
|
|
518
|
+
used_trampolines &= ~(1u << idx);
|
|
519
|
+
|
|
520
|
+
uint64_t *gpr_ptr = (uint64_t *)own_sp;
|
|
521
|
+
uint64_t *vec_ptr = gpr_ptr + 8;
|
|
522
|
+
uint64_t *args_ptr = (uint64_t *)caller_sp;
|
|
523
|
+
|
|
524
|
+
uint8_t *return_ptr = proto->ret.use_memory ? (uint8_t *)gpr_ptr[0] : nullptr;
|
|
525
|
+
gpr_ptr += proto->ret.use_memory;
|
|
526
|
+
|
|
527
|
+
LocalArray<napi_value, MaxParameters> arguments;
|
|
528
|
+
|
|
529
|
+
// Convert to JS arguments
|
|
530
|
+
for (Size i = 0; i < proto->parameters.len; i++) {
|
|
531
|
+
const ParameterInfo ¶m = proto->parameters[i];
|
|
532
|
+
RG_ASSERT(param.directions >= 1 && param.directions <= 3);
|
|
533
|
+
|
|
534
|
+
switch (param.type->primitive) {
|
|
535
|
+
case PrimitiveKind::Void: { RG_UNREACHABLE(); } break;
|
|
536
|
+
|
|
537
|
+
case PrimitiveKind::Bool: {
|
|
538
|
+
bool b = *(bool *)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
539
|
+
|
|
540
|
+
Napi::Value arg = Napi::Boolean::New(env, b);
|
|
541
|
+
arguments.Append(arg);
|
|
542
|
+
} break;
|
|
543
|
+
case PrimitiveKind::Int8: {
|
|
544
|
+
double d = (double)*(int8_t *)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
545
|
+
|
|
546
|
+
Napi::Value arg = Napi::Number::New(env, d);
|
|
547
|
+
arguments.Append(arg);
|
|
548
|
+
} break;
|
|
549
|
+
case PrimitiveKind::UInt8: {
|
|
550
|
+
double d = (double)*(uint8_t *)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
551
|
+
|
|
552
|
+
Napi::Value arg = Napi::Number::New(env, d);
|
|
553
|
+
arguments.Append(arg);
|
|
554
|
+
} break;
|
|
555
|
+
case PrimitiveKind::Int16: {
|
|
556
|
+
double d = (double)*(int16_t *)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
557
|
+
|
|
558
|
+
Napi::Value arg = Napi::Number::New(env, d);
|
|
559
|
+
arguments.Append(arg);
|
|
560
|
+
} break;
|
|
561
|
+
case PrimitiveKind::UInt16: {
|
|
562
|
+
double d = (double)*(uint16_t *)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
563
|
+
|
|
564
|
+
Napi::Value arg = Napi::Number::New(env, d);
|
|
565
|
+
arguments.Append(arg);
|
|
566
|
+
} break;
|
|
567
|
+
case PrimitiveKind::Int32: {
|
|
568
|
+
double d = (double)*(int32_t *)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
569
|
+
|
|
570
|
+
Napi::Value arg = Napi::Number::New(env, d);
|
|
571
|
+
arguments.Append(arg);
|
|
572
|
+
} break;
|
|
573
|
+
case PrimitiveKind::UInt32: {
|
|
574
|
+
double d = (double)*(int32_t *)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
575
|
+
|
|
576
|
+
Napi::Value arg = Napi::Number::New(env, d);
|
|
577
|
+
arguments.Append(arg);
|
|
578
|
+
} break;
|
|
579
|
+
case PrimitiveKind::Int64: {
|
|
580
|
+
int64_t v = *(int64_t *)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
581
|
+
|
|
582
|
+
Napi::Value arg = Napi::BigInt::New(env, v);
|
|
583
|
+
arguments.Append(arg);
|
|
584
|
+
} break;
|
|
585
|
+
case PrimitiveKind::UInt64: {
|
|
586
|
+
uint64_t v = *(uint64_t *)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
587
|
+
|
|
588
|
+
Napi::Value arg = Napi::BigInt::New(env, v);
|
|
589
|
+
arguments.Append(arg);
|
|
590
|
+
} break;
|
|
591
|
+
case PrimitiveKind::String: {
|
|
592
|
+
const char *str = *(const char **)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
593
|
+
|
|
594
|
+
Napi::Value arg = Napi::String::New(env, str);
|
|
595
|
+
arguments.Append(arg);
|
|
596
|
+
} break;
|
|
597
|
+
case PrimitiveKind::String16: {
|
|
598
|
+
const char16_t *str16 = *(const char16_t **)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
599
|
+
|
|
600
|
+
Napi::Value arg = Napi::String::New(env, str16);
|
|
601
|
+
arguments.Append(arg);
|
|
602
|
+
} break;
|
|
603
|
+
case PrimitiveKind::Pointer:
|
|
604
|
+
case PrimitiveKind::Callback: {
|
|
605
|
+
void *ptr2 = *(void **)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
606
|
+
|
|
607
|
+
if (ptr2) {
|
|
608
|
+
Napi::External<void> external = Napi::External<void>::New(env, ptr2);
|
|
609
|
+
SetValueTag(instance, external, param.type);
|
|
610
|
+
|
|
611
|
+
arguments.Append(external);
|
|
612
|
+
} else {
|
|
613
|
+
arguments.Append(env.Null());
|
|
614
|
+
}
|
|
615
|
+
} break;
|
|
616
|
+
case PrimitiveKind::Record: {
|
|
617
|
+
if (!param.use_memory) {
|
|
618
|
+
uint64_t buf[2] = {};
|
|
619
|
+
uint64_t *ptr = buf;
|
|
620
|
+
|
|
621
|
+
if (param.gpr_first) {
|
|
622
|
+
*(ptr++) = *(gpr_ptr++);
|
|
623
|
+
*(ptr++) = *((param.vec_count ? vec_ptr : gpr_ptr)++);
|
|
624
|
+
gpr_ptr -= (param.gpr_count == 1);
|
|
625
|
+
} else if (param.vec_count) {
|
|
626
|
+
*(ptr++) = *(vec_ptr++);
|
|
627
|
+
*(ptr++) = *((param.gpr_count ? gpr_ptr : vec_ptr)++);
|
|
628
|
+
} else {
|
|
629
|
+
RG_ASSERT(param.type->align <= 8);
|
|
630
|
+
|
|
631
|
+
memcpy_safe(ptr, args_ptr, param.type->size);
|
|
632
|
+
args_ptr += (param.type->size + 7) / 8;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
// Reassemble float or mixed int-float structs from registers
|
|
636
|
+
int realign = param.vec_count ? 8 : 0;
|
|
637
|
+
|
|
638
|
+
Napi::Object obj = PopObject((const uint8_t *)buf, param.type, realign);
|
|
639
|
+
arguments.Append(obj);
|
|
640
|
+
} else {
|
|
641
|
+
uint8_t *ptr = *(uint8_t **)((param.gpr_count ? gpr_ptr : args_ptr)++);
|
|
642
|
+
|
|
643
|
+
Napi::Object obj = PopObject(ptr, param.type);
|
|
644
|
+
arguments.Append(obj);
|
|
645
|
+
}
|
|
646
|
+
} break;
|
|
647
|
+
case PrimitiveKind::Array: { RG_UNREACHABLE(); } break;
|
|
648
|
+
case PrimitiveKind::Float32: {
|
|
649
|
+
float f;
|
|
650
|
+
if (RG_LIKELY(param.vec_count)) {
|
|
651
|
+
f = *(float *)(vec_ptr++);
|
|
652
|
+
} else if (param.gpr_count) {
|
|
653
|
+
f = *(float *)(gpr_ptr++);
|
|
654
|
+
} else {
|
|
655
|
+
f = *(float *)(args_ptr++);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
Napi::Value arg = Napi::Number::New(env, (double)f);
|
|
659
|
+
arguments.Append(arg);
|
|
660
|
+
} break;
|
|
661
|
+
case PrimitiveKind::Float64: {
|
|
662
|
+
double d;
|
|
663
|
+
if (RG_LIKELY(param.vec_count)) {
|
|
664
|
+
d = *(double *)(vec_ptr++);
|
|
665
|
+
} else if (param.gpr_count) {
|
|
666
|
+
d = *(double *)(gpr_ptr++);
|
|
667
|
+
} else {
|
|
668
|
+
d = *(double *)(args_ptr++);
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
Napi::Value arg = Napi::Number::New(env, d);
|
|
672
|
+
arguments.Append(arg);
|
|
673
|
+
} break;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
const TypeInfo *type = proto->ret.type;
|
|
678
|
+
|
|
679
|
+
// Make the call
|
|
680
|
+
napi_value ret = CallSwitchStack(&func, (size_t)arguments.len, arguments.data, old_sp, &mem->stack,
|
|
681
|
+
[](Napi::Function *func, size_t argc, napi_value *argv) { return (napi_value)func->Call(argc, argv); });
|
|
682
|
+
Napi::Value value(env, ret);
|
|
683
|
+
|
|
684
|
+
// Convert the result
|
|
685
|
+
switch (type->primitive) {
|
|
686
|
+
case PrimitiveKind::Void: {} break;
|
|
687
|
+
case PrimitiveKind::Bool: {
|
|
688
|
+
if (RG_UNLIKELY(!value.IsBoolean())) {
|
|
689
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected boolean", GetValueType(instance, value));
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
bool b = value.As<Napi::Boolean>();
|
|
694
|
+
out_reg->a0 = (uint64_t)b;
|
|
695
|
+
} break;
|
|
696
|
+
case PrimitiveKind::Int8:
|
|
697
|
+
case PrimitiveKind::UInt8:
|
|
698
|
+
case PrimitiveKind::Int16:
|
|
699
|
+
case PrimitiveKind::UInt16:
|
|
700
|
+
case PrimitiveKind::Int32:
|
|
701
|
+
case PrimitiveKind::UInt32:
|
|
702
|
+
case PrimitiveKind::Int64:
|
|
703
|
+
case PrimitiveKind::UInt64: {
|
|
704
|
+
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
705
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected number", GetValueType(instance, value));
|
|
706
|
+
return;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
int64_t v = CopyNumber<int64_t>(value);
|
|
710
|
+
out_reg->a0 = (uint64_t)v;
|
|
711
|
+
} break;
|
|
712
|
+
case PrimitiveKind::String: {
|
|
713
|
+
const char *str;
|
|
714
|
+
if (RG_LIKELY(value.IsString())) {
|
|
715
|
+
str = PushString(value);
|
|
716
|
+
if (RG_UNLIKELY(!str))
|
|
717
|
+
return;
|
|
718
|
+
} else if (IsNullOrUndefined(value)) {
|
|
719
|
+
str = nullptr;
|
|
720
|
+
} else {
|
|
721
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected string", GetValueType(instance, value));
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
out_reg->a0 = (uint64_t)str;
|
|
726
|
+
} break;
|
|
727
|
+
case PrimitiveKind::String16: {
|
|
728
|
+
const char16_t *str16;
|
|
729
|
+
if (RG_LIKELY(value.IsString())) {
|
|
730
|
+
str16 = PushString16(value);
|
|
731
|
+
if (RG_UNLIKELY(!str16))
|
|
732
|
+
return;
|
|
733
|
+
} else if (IsNullOrUndefined(value)) {
|
|
734
|
+
str16 = nullptr;
|
|
735
|
+
} else {
|
|
736
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected string", GetValueType(instance, value));
|
|
737
|
+
return;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
out_reg->a0 = (uint64_t)str16;
|
|
741
|
+
} break;
|
|
742
|
+
case PrimitiveKind::Pointer: {
|
|
743
|
+
uint8_t *ptr;
|
|
744
|
+
|
|
745
|
+
if (CheckValueTag(instance, value, type)) {
|
|
746
|
+
ptr = value.As<Napi::External<uint8_t>>().Data();
|
|
747
|
+
} else if (IsObject(value) && type->ref->primitive == PrimitiveKind::Record) {
|
|
748
|
+
Napi::Object obj = value.As<Napi::Object>();
|
|
749
|
+
|
|
750
|
+
if (RG_UNLIKELY(!AllocHeap(type->ref->size, 16, &ptr)))
|
|
751
|
+
return;
|
|
752
|
+
|
|
753
|
+
if (!PushObject(obj, type->ref, ptr))
|
|
754
|
+
return;
|
|
755
|
+
} else if (IsNullOrUndefined(value)) {
|
|
756
|
+
ptr = nullptr;
|
|
757
|
+
} else {
|
|
758
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected %2", GetValueType(instance, value), type->name);
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
out_reg->a0 = (uint64_t)ptr;
|
|
763
|
+
} break;
|
|
764
|
+
case PrimitiveKind::Record: {
|
|
765
|
+
if (RG_UNLIKELY(!IsObject(value))) {
|
|
766
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected object", GetValueType(instance, value));
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
Napi::Object obj = value.As<Napi::Object>();
|
|
771
|
+
|
|
772
|
+
if (return_ptr) {
|
|
773
|
+
if (!PushObject(obj, type, return_ptr))
|
|
774
|
+
return;
|
|
775
|
+
out_reg->a0 = (uint64_t)return_ptr;
|
|
776
|
+
} else if (proto->ret.vec_count) { // HFA
|
|
777
|
+
PushObject(obj, type, (uint8_t *)&out_reg->fa0, 8);
|
|
778
|
+
} else {
|
|
779
|
+
PushObject(obj, type, (uint8_t *)&out_reg->a0);
|
|
780
|
+
}
|
|
781
|
+
} break;
|
|
782
|
+
case PrimitiveKind::Array: { RG_UNREACHABLE(); } break;
|
|
783
|
+
case PrimitiveKind::Float32: {
|
|
784
|
+
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
785
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected number", GetValueType(instance, value));
|
|
786
|
+
return;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
float f = CopyNumber<float>(value);
|
|
790
|
+
memset((uint8_t *)&out_reg->fa0 + 4, 0xFF, 4);
|
|
791
|
+
memcpy(&out_reg->fa0, &f, 4);
|
|
792
|
+
} break;
|
|
793
|
+
case PrimitiveKind::Float64: {
|
|
794
|
+
if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
|
|
795
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected number", GetValueType(instance, value));
|
|
796
|
+
return;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
double d = CopyNumber<double>(value);
|
|
800
|
+
out_reg->fa0 = d;
|
|
801
|
+
} break;
|
|
802
|
+
case PrimitiveKind::Callback: {
|
|
803
|
+
void *ptr;
|
|
804
|
+
|
|
805
|
+
if (value.IsFunction()) {
|
|
806
|
+
Napi::Function func = value.As<Napi::Function>();
|
|
807
|
+
|
|
808
|
+
Size idx = ReserveTrampoline(type->proto, func);
|
|
809
|
+
if (RG_UNLIKELY(idx < 0))
|
|
810
|
+
return;
|
|
811
|
+
|
|
812
|
+
ptr = GetTrampoline(idx, type->proto);
|
|
813
|
+
} else if (CheckValueTag(instance, value, type)) {
|
|
814
|
+
ptr = value.As<Napi::External<uint8_t>>().Data();
|
|
815
|
+
} else if (IsNullOrUndefined(value)) {
|
|
816
|
+
ptr = nullptr;
|
|
817
|
+
} else {
|
|
818
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for return value, expected %2", GetValueType(instance, value), type->name);
|
|
819
|
+
return;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
out_reg->a0 = (uint64_t)ptr;
|
|
823
|
+
} break;
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
void *GetTrampoline(Size idx, const FunctionInfo *proto)
|
|
828
|
+
{
|
|
829
|
+
bool fp = proto->forward_fp || proto->ret.vec_count;
|
|
830
|
+
return Trampolines[idx][fp];
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
extern "C" void RelayCallBack(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
|
|
834
|
+
{
|
|
835
|
+
exec_call->Relay(idx, own_sp, caller_sp, out_reg);
|
|
836
|
+
}
|
|
837
|
+
|
|
466
838
|
}
|
|
467
839
|
|
|
468
840
|
#endif
|