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.
@@ -39,17 +39,67 @@ struct Fa0Fa1Ret {
39
39
  double fa1;
40
40
  };
41
41
 
42
- extern "C" A0A1Ret ForwardCallGG(const void *func, uint8_t *sp);
43
- extern "C" float ForwardCallF(const void *func, uint8_t *sp);
44
- extern "C" Fa0A0Ret ForwardCallDG(const void *func, uint8_t *sp);
45
- extern "C" A0Fa0Ret ForwardCallGD(const void *func, uint8_t *sp);
46
- extern "C" Fa0Fa1Ret ForwardCallDD(const void *func, uint8_t *sp);
47
-
48
- extern "C" A0A1Ret ForwardCallXGG(const void *func, uint8_t *sp);
49
- extern "C" float ForwardCallXF(const void *func, uint8_t *sp);
50
- extern "C" Fa0A0Ret ForwardCallXDG(const void *func, uint8_t *sp);
51
- extern "C" A0Fa0Ret ForwardCallXGD(const void *func, uint8_t *sp);
52
- extern "C" Fa0Fa1Ret ForwardCallXDD(const void *func, uint8_t *sp);
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
- uint8_t *args_ptr = nullptr;
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
- if (RG_LIKELY(param.gpr_count)) {
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
- if (RG_LIKELY(param.gpr_count)) {
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
- if (RG_LIKELY(param.gpr_count)) {
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 += AlignLen(param.type->size, 8);
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 + 4, 0xFF, 4);
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
- sp = mem->stack.end();
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, sp) \
378
- : ForwardCall ## Suffix(func->func, sp)); \
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: { result.u64 = PERFORM_CALL(GG).a0; } break;
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
- Napi::External<void> external = Napi::External<void>::New(env, result.ptr);
442
- SetValueTag(instance, external, func->ret.type);
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
- return external;
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 &param = 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