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