koffi 1.3.12 → 2.1.0-beta.1

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.
Files changed (104) hide show
  1. package/CMakeLists.txt +8 -10
  2. package/ChangeLog.md +48 -16
  3. package/README.md +6 -0
  4. package/benchmark/atoi_koffi.js +12 -8
  5. package/benchmark/atoi_napi.js +12 -8
  6. package/benchmark/atoi_node_ffi.js +11 -10
  7. package/benchmark/raylib_cc.cc +12 -9
  8. package/benchmark/raylib_koffi.js +15 -13
  9. package/benchmark/raylib_node_ffi.js +15 -13
  10. package/benchmark/raylib_node_raylib.js +14 -11
  11. package/build/qemu/2.1.0-beta.1/koffi_darwin_arm64.tar.gz +0 -0
  12. package/build/qemu/2.1.0-beta.1/koffi_darwin_x64.tar.gz +0 -0
  13. package/build/qemu/2.1.0-beta.1/koffi_freebsd_arm64.tar.gz +0 -0
  14. package/build/qemu/2.1.0-beta.1/koffi_freebsd_ia32.tar.gz +0 -0
  15. package/build/qemu/2.1.0-beta.1/koffi_freebsd_x64.tar.gz +0 -0
  16. package/build/qemu/2.1.0-beta.1/koffi_linux_arm32hf.tar.gz +0 -0
  17. package/build/qemu/2.1.0-beta.1/koffi_linux_arm64.tar.gz +0 -0
  18. package/build/qemu/2.1.0-beta.1/koffi_linux_ia32.tar.gz +0 -0
  19. package/build/qemu/2.1.0-beta.1/koffi_linux_riscv64hf64.tar.gz +0 -0
  20. package/build/qemu/2.1.0-beta.1/koffi_linux_x64.tar.gz +0 -0
  21. package/build/qemu/2.1.0-beta.1/koffi_openbsd_ia32.tar.gz +0 -0
  22. package/build/qemu/2.1.0-beta.1/koffi_openbsd_x64.tar.gz +0 -0
  23. package/build/qemu/2.1.0-beta.1/koffi_win32_arm64.tar.gz +0 -0
  24. package/build/qemu/2.1.0-beta.1/koffi_win32_ia32.tar.gz +0 -0
  25. package/build/qemu/2.1.0-beta.1/koffi_win32_x64.tar.gz +0 -0
  26. package/doc/changes.md +160 -1
  27. package/doc/conf.py +14 -1
  28. package/doc/contribute.md +0 -1
  29. package/doc/dist/doctrees/benchmarks.doctree +0 -0
  30. package/doc/dist/doctrees/changes.doctree +0 -0
  31. package/doc/dist/doctrees/environment.pickle +0 -0
  32. package/doc/dist/doctrees/functions.doctree +0 -0
  33. package/doc/dist/doctrees/index.doctree +0 -0
  34. package/doc/dist/doctrees/types.doctree +0 -0
  35. package/doc/dist/html/.buildinfo +1 -1
  36. package/doc/dist/html/_sources/benchmarks.md.txt +2 -2
  37. package/doc/dist/html/_sources/changes.md.txt +160 -1
  38. package/doc/dist/html/_sources/functions.md.txt +17 -13
  39. package/doc/dist/html/_sources/types.md.txt +87 -35
  40. package/doc/dist/html/benchmarks.html +7 -3
  41. package/doc/dist/html/changes.html +241 -14
  42. package/doc/dist/html/contribute.html +5 -1
  43. package/doc/dist/html/functions.html +30 -23
  44. package/doc/dist/html/genindex.html +5 -1
  45. package/doc/dist/html/index.html +13 -19
  46. package/doc/dist/html/memory.html +7 -3
  47. package/doc/dist/html/objects.inv +0 -0
  48. package/doc/dist/html/platforms.html +6 -2
  49. package/doc/dist/html/search.html +5 -1
  50. package/doc/dist/html/searchindex.js +1 -1
  51. package/doc/dist/html/start.html +5 -1
  52. package/doc/dist/html/types.html +104 -43
  53. package/doc/functions.md +139 -15
  54. package/doc/templates/badges.html +5 -0
  55. package/doc/types.md +108 -40
  56. package/package.json +2 -2
  57. package/qemu/qemu.js +1 -1
  58. package/qemu/registry/machines.json +5 -5
  59. package/qemu/registry/sha256sum.txt +16 -16
  60. package/src/abi_arm32.cc +91 -19
  61. package/src/abi_arm32_fwd.S +121 -57
  62. package/src/abi_arm64.cc +91 -19
  63. package/src/abi_arm64_fwd.S +96 -0
  64. package/src/abi_arm64_fwd.asm +128 -0
  65. package/src/abi_riscv64.cc +89 -19
  66. package/src/abi_riscv64_fwd.S +96 -0
  67. package/src/abi_x64_sysv.cc +94 -22
  68. package/src/abi_x64_sysv_fwd.S +96 -0
  69. package/src/abi_x64_win.cc +89 -19
  70. package/src/abi_x64_win_fwd.asm +128 -0
  71. package/src/abi_x86.cc +94 -19
  72. package/src/abi_x86_fwd.S +96 -0
  73. package/src/abi_x86_fwd.asm +128 -0
  74. package/src/call.cc +128 -78
  75. package/src/call.hh +17 -4
  76. package/src/ffi.cc +514 -145
  77. package/src/ffi.hh +30 -9
  78. package/src/index.js +4 -2
  79. package/src/parser.cc +19 -44
  80. package/src/util.cc +160 -27
  81. package/src/util.hh +7 -2
  82. package/test/async.js +1 -2
  83. package/test/callbacks.js +56 -11
  84. package/test/misc.c +50 -15
  85. package/test/raylib.js +2 -2
  86. package/test/sqlite.js +27 -19
  87. package/test/sync.js +71 -35
  88. package/vendor/libcc/libcc.cc +18 -5
  89. package/vendor/libcc/libcc.hh +70 -23
  90. package/build/qemu/1.3.12/koffi_darwin_arm64.tar.gz +0 -0
  91. package/build/qemu/1.3.12/koffi_darwin_x64.tar.gz +0 -0
  92. package/build/qemu/1.3.12/koffi_freebsd_arm64.tar.gz +0 -0
  93. package/build/qemu/1.3.12/koffi_freebsd_ia32.tar.gz +0 -0
  94. package/build/qemu/1.3.12/koffi_freebsd_x64.tar.gz +0 -0
  95. package/build/qemu/1.3.12/koffi_linux_arm32hf.tar.gz +0 -0
  96. package/build/qemu/1.3.12/koffi_linux_arm64.tar.gz +0 -0
  97. package/build/qemu/1.3.12/koffi_linux_ia32.tar.gz +0 -0
  98. package/build/qemu/1.3.12/koffi_linux_riscv64hf64.tar.gz +0 -0
  99. package/build/qemu/1.3.12/koffi_linux_x64.tar.gz +0 -0
  100. package/build/qemu/1.3.12/koffi_openbsd_ia32.tar.gz +0 -0
  101. package/build/qemu/1.3.12/koffi_openbsd_x64.tar.gz +0 -0
  102. package/build/qemu/1.3.12/koffi_win32_arm64.tar.gz +0 -0
  103. package/build/qemu/1.3.12/koffi_win32_ia32.tar.gz +0 -0
  104. package/build/qemu/1.3.12/koffi_win32_x64.tar.gz +0 -0
@@ -81,6 +81,22 @@ extern "C" int Trampoline12; extern "C" int TrampolineX12;
81
81
  extern "C" int Trampoline13; extern "C" int TrampolineX13;
82
82
  extern "C" int Trampoline14; extern "C" int TrampolineX14;
83
83
  extern "C" int Trampoline15; extern "C" int TrampolineX15;
84
+ extern "C" int Trampoline16; extern "C" int TrampolineX16;
85
+ extern "C" int Trampoline17; extern "C" int TrampolineX17;
86
+ extern "C" int Trampoline18; extern "C" int TrampolineX18;
87
+ extern "C" int Trampoline19; extern "C" int TrampolineX19;
88
+ extern "C" int Trampoline20; extern "C" int TrampolineX20;
89
+ extern "C" int Trampoline21; extern "C" int TrampolineX21;
90
+ extern "C" int Trampoline22; extern "C" int TrampolineX22;
91
+ extern "C" int Trampoline23; extern "C" int TrampolineX23;
92
+ extern "C" int Trampoline24; extern "C" int TrampolineX24;
93
+ extern "C" int Trampoline25; extern "C" int TrampolineX25;
94
+ extern "C" int Trampoline26; extern "C" int TrampolineX26;
95
+ extern "C" int Trampoline27; extern "C" int TrampolineX27;
96
+ extern "C" int Trampoline28; extern "C" int TrampolineX28;
97
+ extern "C" int Trampoline29; extern "C" int TrampolineX29;
98
+ extern "C" int Trampoline30; extern "C" int TrampolineX30;
99
+ extern "C" int Trampoline31; extern "C" int TrampolineX31;
84
100
 
85
101
  extern "C" napi_value CallSwitchStack(Napi::Function *func, size_t argc, napi_value *argv,
86
102
  uint8_t *old_sp, Span<uint8_t> *new_stack,
@@ -102,9 +118,25 @@ static void *const Trampolines[][2] = {
102
118
  { &Trampoline12, &TrampolineX12 },
103
119
  { &Trampoline13, &TrampolineX13 },
104
120
  { &Trampoline14, &TrampolineX14 },
105
- { &Trampoline15, &TrampolineX15 }
121
+ { &Trampoline15, &TrampolineX15 },
122
+ { &Trampoline16, &TrampolineX16 },
123
+ { &Trampoline17, &TrampolineX17 },
124
+ { &Trampoline18, &TrampolineX18 },
125
+ { &Trampoline19, &TrampolineX19 },
126
+ { &Trampoline20, &TrampolineX20 },
127
+ { &Trampoline21, &TrampolineX21 },
128
+ { &Trampoline22, &TrampolineX22 },
129
+ { &Trampoline23, &TrampolineX23 },
130
+ { &Trampoline24, &TrampolineX24 },
131
+ { &Trampoline25, &TrampolineX25 },
132
+ { &Trampoline26, &TrampolineX26 },
133
+ { &Trampoline27, &TrampolineX27 },
134
+ { &Trampoline28, &TrampolineX28 },
135
+ { &Trampoline29, &TrampolineX29 },
136
+ { &Trampoline30, &TrampolineX30 },
137
+ { &Trampoline31, &TrampolineX31 }
106
138
  };
107
- RG_STATIC_ASSERT(RG_LEN(Trampolines) == MaxTrampolines);
139
+ RG_STATIC_ASSERT(RG_LEN(Trampolines) == MaxTrampolines * 2);
108
140
 
109
141
  static RG_THREAD_LOCAL CallData *exec_call;
110
142
 
@@ -169,12 +201,12 @@ static Size ClassifyType(const TypeInfo *type, Size offset, Span<RegisterClass>
169
201
  return 1;
170
202
  }
171
203
 
172
- Size len = type->size / type->ref->size;
204
+ Size len = type->size / type->ref.type->size;
173
205
 
174
206
  for (Size i = 0; i < len; i++) {
175
207
  Size start = offset / 8;
176
- ClassifyType(type->ref, offset % 8, classes.Take(start, classes.len - start));
177
- offset += type->ref->size;
208
+ ClassifyType(type->ref.type, offset % 8, classes.Take(start, classes.len - start));
209
+ offset += type->ref.type->size;
178
210
  }
179
211
 
180
212
  return (offset + 7) / 8;
@@ -184,6 +216,8 @@ static Size ClassifyType(const TypeInfo *type, Size offset, Span<RegisterClass>
184
216
  classes[0] = MergeClasses(classes[0], RegisterClass::SSE);
185
217
  return 1;
186
218
  } break;
219
+
220
+ case PrimitiveKind::Prototype: { RG_UNREACHABLE(); } break;
187
221
  }
188
222
 
189
223
  RG_UNREACHABLE();
@@ -410,10 +444,10 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
410
444
  if (value.IsFunction()) {
411
445
  Napi::Function func = value.As<Napi::Function>();
412
446
 
413
- ptr = ReserveTrampoline(param.type->proto, func);
447
+ ptr = ReserveTrampoline(param.type->ref.proto, func);
414
448
  if (RG_UNLIKELY(!ptr))
415
449
  return false;
416
- } else if (CheckValueTag(instance, value, param.type)) {
450
+ } else if (CheckValueTag(instance, value, param.type->ref.marker)) {
417
451
  ptr = value.As<Napi::External<void>>().Data();
418
452
  } else if (IsNullOrUndefined(value)) {
419
453
  ptr = nullptr;
@@ -424,6 +458,8 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
424
458
 
425
459
  *(void **)((param.gpr_count ? gpr_ptr : args_ptr)++) = ptr;
426
460
  } break;
461
+
462
+ case PrimitiveKind::Prototype: { RG_UNREACHABLE(); } break;
427
463
  }
428
464
  }
429
465
 
@@ -477,6 +513,8 @@ void CallData::Execute()
477
513
  case PrimitiveKind::Array: { RG_UNREACHABLE(); } break;
478
514
  case PrimitiveKind::Float32: { result.f = PERFORM_CALL(F); } break;
479
515
  case PrimitiveKind::Float64: { result.d = PERFORM_CALL(DG).xmm0; } break;
516
+
517
+ case PrimitiveKind::Prototype: { RG_UNREACHABLE(); } break;
480
518
  }
481
519
 
482
520
  #undef PERFORM_CALL
@@ -484,10 +522,16 @@ void CallData::Execute()
484
522
 
485
523
  Napi::Value CallData::Complete()
486
524
  {
487
- PopOutArguments();
525
+ RG_DEFER {
526
+ PopOutArguments();
527
+
528
+ if (func->ret.type->dispose) {
529
+ func->ret.type->dispose(env, func->ret.type, result.ptr);
530
+ }
531
+ };
488
532
 
489
533
  switch (func->ret.type->primitive) {
490
- case PrimitiveKind::Void: return env.Null();
534
+ case PrimitiveKind::Void: return env.Undefined();
491
535
  case PrimitiveKind::Bool: return Napi::Boolean::New(env, result.u32);
492
536
  case PrimitiveKind::Int8: return Napi::Number::New(env, (double)result.i8);
493
537
  case PrimitiveKind::UInt8: return Napi::Number::New(env, (double)result.u8);
@@ -503,7 +547,7 @@ Napi::Value CallData::Complete()
503
547
  case PrimitiveKind::Callback: {
504
548
  if (result.ptr) {
505
549
  Napi::External<void> external = Napi::External<void>::New(env, result.ptr);
506
- SetValueTag(instance, external, func->ret.type);
550
+ SetValueTag(instance, external, func->ret.type->ref.marker);
507
551
 
508
552
  return external;
509
553
  } else {
@@ -520,6 +564,8 @@ Napi::Value CallData::Complete()
520
564
  case PrimitiveKind::Array: { RG_UNREACHABLE(); } break;
521
565
  case PrimitiveKind::Float32: return Napi::Number::New(env, (double)result.f);
522
566
  case PrimitiveKind::Float64: return Napi::Number::New(env, result.d);
567
+
568
+ case PrimitiveKind::Prototype: { RG_UNREACHABLE(); } break;
523
569
  }
524
570
 
525
571
  RG_UNREACHABLE();
@@ -527,12 +573,10 @@ Napi::Value CallData::Complete()
527
573
 
528
574
  void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
529
575
  {
530
- const TrampolineInfo &trampoline = instance->trampolines[idx];
531
-
532
- if (RG_UNLIKELY(trampoline.generation != mem->generation)) {
533
- ThrowError<Napi::Error>(env, "Cannot use non-persistent callback beyond FFI call");
576
+ if (RG_UNLIKELY(env.IsExceptionPending()))
534
577
  return;
535
- }
578
+
579
+ const TrampolineInfo &trampoline = instance->trampolines[idx];
536
580
 
537
581
  const FunctionInfo *proto = trampoline.proto;
538
582
  Napi::Function func = trampoline.func.Value();
@@ -544,6 +588,13 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
544
588
  uint8_t *return_ptr = proto->ret.use_memory ? (uint8_t *)gpr_ptr[0] : nullptr;
545
589
  gpr_ptr += proto->ret.use_memory;
546
590
 
591
+ RG_DEFER_N(err_guard) { memset(out_reg, 0, RG_SIZE(*out_reg)); };
592
+
593
+ if (RG_UNLIKELY(trampoline.generation >= 0 && trampoline.generation != (int32_t)mem->generation)) {
594
+ ThrowError<Napi::Error>(env, "Cannot use non-registered callback beyond FFI call");
595
+ return;
596
+ }
597
+
547
598
  LocalArray<napi_value, MaxParameters> arguments;
548
599
 
549
600
  // Convert to JS arguments
@@ -613,12 +664,20 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
613
664
 
614
665
  Napi::Value arg = str ? Napi::String::New(env, str) : env.Null();
615
666
  arguments.Append(arg);
667
+
668
+ if (param.type->dispose) {
669
+ param.type->dispose(env, param.type, str);
670
+ }
616
671
  } break;
617
672
  case PrimitiveKind::String16: {
618
673
  const char16_t *str16 = *(const char16_t **)((param.gpr_count ? gpr_ptr : args_ptr)++);
619
674
 
620
675
  Napi::Value arg = str16 ? Napi::String::New(env, str16) : env.Null();
621
676
  arguments.Append(arg);
677
+
678
+ if (param.type->dispose) {
679
+ param.type->dispose(env, param.type, str16);
680
+ }
622
681
  } break;
623
682
  case PrimitiveKind::Pointer:
624
683
  case PrimitiveKind::Callback: {
@@ -626,12 +685,16 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
626
685
 
627
686
  if (ptr2) {
628
687
  Napi::External<void> external = Napi::External<void>::New(env, ptr2);
629
- SetValueTag(instance, external, param.type);
688
+ SetValueTag(instance, external, param.type->ref.marker);
630
689
 
631
690
  arguments.Append(external);
632
691
  } else {
633
692
  arguments.Append(env.Null());
634
693
  }
694
+
695
+ if (param.type->dispose) {
696
+ param.type->dispose(env, param.type, ptr2);
697
+ }
635
698
  } break;
636
699
  case PrimitiveKind::Record: {
637
700
  if (param.gpr_count || param.xmm_count) {
@@ -680,6 +743,8 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
680
743
  Napi::Value arg = Napi::Number::New(env, d);
681
744
  arguments.Append(arg);
682
745
  } break;
746
+
747
+ case PrimitiveKind::Prototype: { RG_UNREACHABLE(); } break;
683
748
  }
684
749
  }
685
750
 
@@ -690,6 +755,9 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
690
755
  [](Napi::Function *func, size_t argc, napi_value *argv) { return (napi_value)func->Call(argc, argv); });
691
756
  Napi::Value value(env, ret);
692
757
 
758
+ if (RG_UNLIKELY(env.IsExceptionPending()))
759
+ return;
760
+
693
761
  // Convert the result
694
762
  switch (type->primitive) {
695
763
  case PrimitiveKind::Void: {} break;
@@ -751,14 +819,14 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
751
819
  case PrimitiveKind::Pointer: {
752
820
  uint8_t *ptr;
753
821
 
754
- if (CheckValueTag(instance, value, type)) {
822
+ if (CheckValueTag(instance, value, type->ref.marker)) {
755
823
  ptr = value.As<Napi::External<uint8_t>>().Data();
756
- } else if (IsObject(value) && type->ref->primitive == PrimitiveKind::Record) {
824
+ } else if (IsObject(value) && type->ref.type->primitive == PrimitiveKind::Record) {
757
825
  Napi::Object obj = value.As<Napi::Object>();
758
826
 
759
- ptr = AllocHeap(type->ref->size, 16);
827
+ ptr = AllocHeap(type->ref.type->size, 16);
760
828
 
761
- if (!PushObject(obj, type->ref, ptr))
829
+ if (!PushObject(obj, type->ref.type, ptr))
762
830
  return;
763
831
  } else if (IsNullOrUndefined(value)) {
764
832
  ptr = nullptr;
@@ -830,10 +898,10 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
830
898
  if (value.IsFunction()) {
831
899
  Napi::Function func2 = value.As<Napi::Function>();
832
900
 
833
- ptr = ReserveTrampoline(type->proto, func2);
901
+ ptr = ReserveTrampoline(type->ref.proto, func2);
834
902
  if (RG_UNLIKELY(!ptr))
835
903
  return;
836
- } else if (CheckValueTag(instance, value, type)) {
904
+ } else if (CheckValueTag(instance, value, type->ref.marker)) {
837
905
  ptr = value.As<Napi::External<uint8_t>>().Data();
838
906
  } else if (IsNullOrUndefined(value)) {
839
907
  ptr = nullptr;
@@ -844,7 +912,11 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
844
912
 
845
913
  out_reg->rax = (uint64_t)ptr;
846
914
  } break;
915
+
916
+ case PrimitiveKind::Prototype: { RG_UNREACHABLE(); } break;
847
917
  }
918
+
919
+ err_guard.Disable();
848
920
  }
849
921
 
850
922
  void *GetTrampoline(Size idx, const FunctionInfo *proto)
@@ -171,6 +171,22 @@ SYMBOL(ForwardCallXDD):
171
171
  .global SYMBOL(Trampoline13)
172
172
  .global SYMBOL(Trampoline14)
173
173
  .global SYMBOL(Trampoline15)
174
+ .global SYMBOL(Trampoline16)
175
+ .global SYMBOL(Trampoline17)
176
+ .global SYMBOL(Trampoline18)
177
+ .global SYMBOL(Trampoline19)
178
+ .global SYMBOL(Trampoline20)
179
+ .global SYMBOL(Trampoline21)
180
+ .global SYMBOL(Trampoline22)
181
+ .global SYMBOL(Trampoline23)
182
+ .global SYMBOL(Trampoline24)
183
+ .global SYMBOL(Trampoline25)
184
+ .global SYMBOL(Trampoline26)
185
+ .global SYMBOL(Trampoline27)
186
+ .global SYMBOL(Trampoline28)
187
+ .global SYMBOL(Trampoline29)
188
+ .global SYMBOL(Trampoline30)
189
+ .global SYMBOL(Trampoline31)
174
190
  .global SYMBOL(TrampolineX0)
175
191
  .global SYMBOL(TrampolineX1)
176
192
  .global SYMBOL(TrampolineX2)
@@ -187,6 +203,22 @@ SYMBOL(ForwardCallXDD):
187
203
  .global SYMBOL(TrampolineX13)
188
204
  .global SYMBOL(TrampolineX14)
189
205
  .global SYMBOL(TrampolineX15)
206
+ .global SYMBOL(TrampolineX16)
207
+ .global SYMBOL(TrampolineX17)
208
+ .global SYMBOL(TrampolineX18)
209
+ .global SYMBOL(TrampolineX19)
210
+ .global SYMBOL(TrampolineX20)
211
+ .global SYMBOL(TrampolineX21)
212
+ .global SYMBOL(TrampolineX22)
213
+ .global SYMBOL(TrampolineX23)
214
+ .global SYMBOL(TrampolineX24)
215
+ .global SYMBOL(TrampolineX25)
216
+ .global SYMBOL(TrampolineX26)
217
+ .global SYMBOL(TrampolineX27)
218
+ .global SYMBOL(TrampolineX28)
219
+ .global SYMBOL(TrampolineX29)
220
+ .global SYMBOL(TrampolineX30)
221
+ .global SYMBOL(TrampolineX31)
190
222
  .global SYMBOL(RelayCallback)
191
223
  .global SYMBOL(CallSwitchStack)
192
224
 
@@ -296,6 +328,38 @@ SYMBOL(Trampoline14):
296
328
  trampoline 14
297
329
  SYMBOL(Trampoline15):
298
330
  trampoline 15
331
+ SYMBOL(Trampoline16):
332
+ trampoline 16
333
+ SYMBOL(Trampoline17):
334
+ trampoline 17
335
+ SYMBOL(Trampoline18):
336
+ trampoline 18
337
+ SYMBOL(Trampoline19):
338
+ trampoline 19
339
+ SYMBOL(Trampoline20):
340
+ trampoline 20
341
+ SYMBOL(Trampoline21):
342
+ trampoline 21
343
+ SYMBOL(Trampoline22):
344
+ trampoline 22
345
+ SYMBOL(Trampoline23):
346
+ trampoline 23
347
+ SYMBOL(Trampoline24):
348
+ trampoline 24
349
+ SYMBOL(Trampoline25):
350
+ trampoline 25
351
+ SYMBOL(Trampoline26):
352
+ trampoline 26
353
+ SYMBOL(Trampoline27):
354
+ trampoline 27
355
+ SYMBOL(Trampoline28):
356
+ trampoline 28
357
+ SYMBOL(Trampoline29):
358
+ trampoline 29
359
+ SYMBOL(Trampoline30):
360
+ trampoline 30
361
+ SYMBOL(Trampoline31):
362
+ trampoline 31
299
363
 
300
364
  SYMBOL(TrampolineX0):
301
365
  trampoline_xmm 0
@@ -329,6 +393,38 @@ SYMBOL(TrampolineX14):
329
393
  trampoline_xmm 14
330
394
  SYMBOL(TrampolineX15):
331
395
  trampoline_xmm 15
396
+ SYMBOL(TrampolineX16):
397
+ trampoline_xmm 16
398
+ SYMBOL(TrampolineX17):
399
+ trampoline_xmm 17
400
+ SYMBOL(TrampolineX18):
401
+ trampoline_xmm 18
402
+ SYMBOL(TrampolineX19):
403
+ trampoline_xmm 19
404
+ SYMBOL(TrampolineX20):
405
+ trampoline_xmm 20
406
+ SYMBOL(TrampolineX21):
407
+ trampoline_xmm 21
408
+ SYMBOL(TrampolineX22):
409
+ trampoline_xmm 22
410
+ SYMBOL(TrampolineX23):
411
+ trampoline_xmm 23
412
+ SYMBOL(TrampolineX24):
413
+ trampoline_xmm 24
414
+ SYMBOL(TrampolineX25):
415
+ trampoline_xmm 25
416
+ SYMBOL(TrampolineX26):
417
+ trampoline_xmm 26
418
+ SYMBOL(TrampolineX27):
419
+ trampoline_xmm 27
420
+ SYMBOL(TrampolineX28):
421
+ trampoline_xmm 28
422
+ SYMBOL(TrampolineX29):
423
+ trampoline_xmm 29
424
+ SYMBOL(TrampolineX30):
425
+ trampoline_xmm 30
426
+ SYMBOL(TrampolineX31):
427
+ trampoline_xmm 31
332
428
 
333
429
  # When a callback is relayed, Koffi will call into Node.js and V8 to execute Javascript.
334
430
  # The problem is that we're still running on the separate Koffi stack, and V8 will
@@ -50,6 +50,22 @@ extern "C" int Trampoline12; extern "C" int TrampolineX12;
50
50
  extern "C" int Trampoline13; extern "C" int TrampolineX13;
51
51
  extern "C" int Trampoline14; extern "C" int TrampolineX14;
52
52
  extern "C" int Trampoline15; extern "C" int TrampolineX15;
53
+ extern "C" int Trampoline16; extern "C" int TrampolineX16;
54
+ extern "C" int Trampoline17; extern "C" int TrampolineX17;
55
+ extern "C" int Trampoline18; extern "C" int TrampolineX18;
56
+ extern "C" int Trampoline19; extern "C" int TrampolineX19;
57
+ extern "C" int Trampoline20; extern "C" int TrampolineX20;
58
+ extern "C" int Trampoline21; extern "C" int TrampolineX21;
59
+ extern "C" int Trampoline22; extern "C" int TrampolineX22;
60
+ extern "C" int Trampoline23; extern "C" int TrampolineX23;
61
+ extern "C" int Trampoline24; extern "C" int TrampolineX24;
62
+ extern "C" int Trampoline25; extern "C" int TrampolineX25;
63
+ extern "C" int Trampoline26; extern "C" int TrampolineX26;
64
+ extern "C" int Trampoline27; extern "C" int TrampolineX27;
65
+ extern "C" int Trampoline28; extern "C" int TrampolineX28;
66
+ extern "C" int Trampoline29; extern "C" int TrampolineX29;
67
+ extern "C" int Trampoline30; extern "C" int TrampolineX30;
68
+ extern "C" int Trampoline31; extern "C" int TrampolineX31;
53
69
 
54
70
  extern "C" napi_value CallSwitchStack(Napi::Function *func, size_t argc, napi_value *argv,
55
71
  uint8_t *old_sp, Span<uint8_t> *new_stack,
@@ -71,9 +87,25 @@ static void *const Trampolines[][2] = {
71
87
  { &Trampoline12, &TrampolineX12 },
72
88
  { &Trampoline13, &TrampolineX13 },
73
89
  { &Trampoline14, &TrampolineX14 },
74
- { &Trampoline15, &TrampolineX15 }
90
+ { &Trampoline15, &TrampolineX15 },
91
+ { &Trampoline16, &TrampolineX16 },
92
+ { &Trampoline17, &TrampolineX17 },
93
+ { &Trampoline18, &TrampolineX18 },
94
+ { &Trampoline19, &TrampolineX19 },
95
+ { &Trampoline20, &TrampolineX20 },
96
+ { &Trampoline21, &TrampolineX21 },
97
+ { &Trampoline22, &TrampolineX22 },
98
+ { &Trampoline23, &TrampolineX23 },
99
+ { &Trampoline24, &TrampolineX24 },
100
+ { &Trampoline25, &TrampolineX25 },
101
+ { &Trampoline26, &TrampolineX26 },
102
+ { &Trampoline27, &TrampolineX27 },
103
+ { &Trampoline28, &TrampolineX28 },
104
+ { &Trampoline29, &TrampolineX29 },
105
+ { &Trampoline30, &TrampolineX30 },
106
+ { &Trampoline31, &TrampolineX31 }
75
107
  };
76
- RG_STATIC_ASSERT(RG_LEN(Trampolines) == MaxTrampolines);
108
+ RG_STATIC_ASSERT(RG_LEN(Trampolines) == MaxTrampolines * 2);
77
109
 
78
110
  static RG_THREAD_LOCAL CallData *exec_call;
79
111
 
@@ -235,10 +267,10 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
235
267
  if (value.IsFunction()) {
236
268
  Napi::Function func = value.As<Napi::Function>();
237
269
 
238
- ptr = ReserveTrampoline(param.type->proto, func);
270
+ ptr = ReserveTrampoline(param.type->ref.proto, func);
239
271
  if (RG_UNLIKELY(!ptr))
240
272
  return false;
241
- } else if (CheckValueTag(instance, value, param.type)) {
273
+ } else if (CheckValueTag(instance, value, param.type->ref.marker)) {
242
274
  ptr = value.As<Napi::External<uint8_t>>().Data();
243
275
  } else if (IsNullOrUndefined(value)) {
244
276
  ptr = nullptr;
@@ -249,6 +281,8 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
249
281
 
250
282
  *(void **)(args_ptr++) = ptr;
251
283
  } break;
284
+
285
+ case PrimitiveKind::Prototype: { RG_UNREACHABLE(); } break;
252
286
  }
253
287
  }
254
288
 
@@ -287,6 +321,8 @@ void CallData::Execute()
287
321
  case PrimitiveKind::Array: { RG_UNREACHABLE(); } break;
288
322
  case PrimitiveKind::Float32: { result.f = PERFORM_CALL(F); } break;
289
323
  case PrimitiveKind::Float64: { result.d = PERFORM_CALL(D); } break;
324
+
325
+ case PrimitiveKind::Prototype: { RG_UNREACHABLE(); } break;
290
326
  }
291
327
 
292
328
  #undef PERFORM_CALL
@@ -294,10 +330,16 @@ void CallData::Execute()
294
330
 
295
331
  Napi::Value CallData::Complete()
296
332
  {
297
- PopOutArguments();
333
+ RG_DEFER {
334
+ PopOutArguments();
335
+
336
+ if (func->ret.type->dispose) {
337
+ func->ret.type->dispose(env, func->ret.type, result.ptr);
338
+ }
339
+ };
298
340
 
299
341
  switch (func->ret.type->primitive) {
300
- case PrimitiveKind::Void: return env.Null();
342
+ case PrimitiveKind::Void: return env.Undefined();
301
343
  case PrimitiveKind::Bool: return Napi::Boolean::New(env, result.u32);
302
344
  case PrimitiveKind::Int8: return Napi::Number::New(env, (double)result.i8);
303
345
  case PrimitiveKind::UInt8: return Napi::Number::New(env, (double)result.u8);
@@ -313,7 +355,7 @@ Napi::Value CallData::Complete()
313
355
  case PrimitiveKind::Callback: {
314
356
  if (result.ptr) {
315
357
  Napi::External<void> external = Napi::External<void>::New(env, result.ptr);
316
- SetValueTag(instance, external, func->ret.type);
358
+ SetValueTag(instance, external, func->ret.type->ref.marker);
317
359
 
318
360
  return external;
319
361
  } else {
@@ -330,6 +372,8 @@ Napi::Value CallData::Complete()
330
372
  case PrimitiveKind::Array: { RG_UNREACHABLE(); } break;
331
373
  case PrimitiveKind::Float32: return Napi::Number::New(env, (double)result.f);
332
374
  case PrimitiveKind::Float64: return Napi::Number::New(env, result.d);
375
+
376
+ case PrimitiveKind::Prototype: { RG_UNREACHABLE(); } break;
333
377
  }
334
378
 
335
379
  RG_UNREACHABLE();
@@ -337,12 +381,10 @@ Napi::Value CallData::Complete()
337
381
 
338
382
  void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
339
383
  {
340
- const TrampolineInfo &trampoline = instance->trampolines[idx];
341
-
342
- if (RG_UNLIKELY(trampoline.generation != mem->generation)) {
343
- ThrowError<Napi::Error>(env, "Cannot use non-persistent callback beyond FFI call");
384
+ if (RG_UNLIKELY(env.IsExceptionPending()))
344
385
  return;
345
- }
386
+
387
+ const TrampolineInfo &trampoline = instance->trampolines[idx];
346
388
 
347
389
  const FunctionInfo *proto = trampoline.proto;
348
390
  Napi::Function func = trampoline.func.Value();
@@ -353,6 +395,13 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
353
395
 
354
396
  uint8_t *return_ptr = !proto->ret.regular ? (uint8_t *)gpr_ptr[0] : nullptr;
355
397
 
398
+ RG_DEFER_N(err_guard) { memset(out_reg, 0, RG_SIZE(*out_reg)); };
399
+
400
+ if (RG_UNLIKELY(trampoline.generation >= 0 && trampoline.generation != (int32_t)mem->generation)) {
401
+ ThrowError<Napi::Error>(env, "Cannot use non-registered callback beyond FFI call");
402
+ return;
403
+ }
404
+
356
405
  LocalArray<napi_value, MaxParameters> arguments;
357
406
 
358
407
  // Convert to JS arguments
@@ -432,6 +481,10 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
432
481
 
433
482
  Napi::Value arg = str ? Napi::String::New(env, str) : env.Null();
434
483
  arguments.Append(arg);
484
+
485
+ if (param.type->dispose) {
486
+ param.type->dispose(env, param.type, str);
487
+ }
435
488
  } break;
436
489
  case PrimitiveKind::String16: {
437
490
  const char16_t *str16 = *(const char16_t **)(j < 4 ? gpr_ptr + j : args_ptr);
@@ -439,6 +492,10 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
439
492
 
440
493
  Napi::Value arg = str16 ? Napi::String::New(env, str16) : env.Null();
441
494
  arguments.Append(arg);
495
+
496
+ if (param.type->dispose) {
497
+ param.type->dispose(env, param.type, str16);
498
+ }
442
499
  } break;
443
500
  case PrimitiveKind::Pointer:
444
501
  case PrimitiveKind::Callback: {
@@ -447,12 +504,16 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
447
504
 
448
505
  if (ptr2) {
449
506
  Napi::External<void> external = Napi::External<void>::New(env, ptr2);
450
- SetValueTag(instance, external, param.type);
507
+ SetValueTag(instance, external, param.type->ref.marker);
451
508
 
452
509
  arguments.Append(external);
453
510
  } else {
454
511
  arguments.Append(env.Null());
455
512
  }
513
+
514
+ if (param.type->dispose) {
515
+ param.type->dispose(env, param.type, ptr2);
516
+ }
456
517
  } break;
457
518
  case PrimitiveKind::Record: {
458
519
  uint8_t *ptr;
@@ -481,6 +542,8 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
481
542
  Napi::Value arg = Napi::Number::New(env, d);
482
543
  arguments.Append(arg);
483
544
  } break;
545
+
546
+ case PrimitiveKind::Prototype: { RG_UNREACHABLE(); } break;
484
547
  }
485
548
  }
486
549
 
@@ -491,6 +554,9 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
491
554
  [](Napi::Function *func, size_t argc, napi_value *argv) { return (napi_value)func->Call(argc, argv); });
492
555
  Napi::Value value(env, ret);
493
556
 
557
+ if (RG_UNLIKELY(env.IsExceptionPending()))
558
+ return;
559
+
494
560
  switch (type->primitive) {
495
561
  case PrimitiveKind::Void: {} break;
496
562
  case PrimitiveKind::Bool: {
@@ -551,14 +617,14 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
551
617
  case PrimitiveKind::Pointer: {
552
618
  uint8_t *ptr;
553
619
 
554
- if (CheckValueTag(instance, value, type)) {
620
+ if (CheckValueTag(instance, value, type->ref.marker)) {
555
621
  ptr = value.As<Napi::External<uint8_t>>().Data();
556
- } else if (IsObject(value) && type->ref->primitive == PrimitiveKind::Record) {
622
+ } else if (IsObject(value) && type->ref.type->primitive == PrimitiveKind::Record) {
557
623
  Napi::Object obj = value.As<Napi::Object>();
558
624
 
559
- ptr = AllocHeap(type->ref->size, 16);
625
+ ptr = AllocHeap(type->ref.type->size, 16);
560
626
 
561
- if (!PushObject(obj, type->ref, ptr))
627
+ if (!PushObject(obj, type->ref.type, ptr))
562
628
  return;
563
629
  } else if (IsNullOrUndefined(value)) {
564
630
  ptr = nullptr;
@@ -612,10 +678,10 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
612
678
  if (value.IsFunction()) {
613
679
  Napi::Function func2 = value.As<Napi::Function>();
614
680
 
615
- ptr = ReserveTrampoline(type->proto, func2);
681
+ ptr = ReserveTrampoline(type->ref.proto, func2);
616
682
  if (RG_UNLIKELY(!ptr))
617
683
  return;
618
- } else if (CheckValueTag(instance, value, type)) {
684
+ } else if (CheckValueTag(instance, value, type->ref.marker)) {
619
685
  ptr = value.As<Napi::External<uint8_t>>().Data();
620
686
  } else if (IsNullOrUndefined(value)) {
621
687
  ptr = nullptr;
@@ -626,7 +692,11 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
626
692
 
627
693
  out_reg->rax = (uint64_t)ptr;
628
694
  } break;
695
+
696
+ case PrimitiveKind::Prototype: { RG_UNREACHABLE(); } break;
629
697
  }
698
+
699
+ err_guard.Disable();
630
700
  }
631
701
 
632
702
  void *GetTrampoline(Size idx, const FunctionInfo *proto)