koffi 1.3.11 → 2.0.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 (94) hide show
  1. package/CMakeLists.txt +7 -2
  2. package/ChangeLog.md +53 -15
  3. package/README.md +6 -0
  4. package/build/qemu/2.0.1/koffi_darwin_arm64.tar.gz +0 -0
  5. package/build/qemu/2.0.1/koffi_darwin_x64.tar.gz +0 -0
  6. package/build/qemu/2.0.1/koffi_freebsd_arm64.tar.gz +0 -0
  7. package/build/qemu/2.0.1/koffi_freebsd_ia32.tar.gz +0 -0
  8. package/build/qemu/2.0.1/koffi_freebsd_x64.tar.gz +0 -0
  9. package/build/qemu/2.0.1/koffi_linux_arm32hf.tar.gz +0 -0
  10. package/build/qemu/2.0.1/koffi_linux_arm64.tar.gz +0 -0
  11. package/build/qemu/2.0.1/koffi_linux_ia32.tar.gz +0 -0
  12. package/build/qemu/2.0.1/koffi_linux_riscv64hf64.tar.gz +0 -0
  13. package/build/qemu/2.0.1/koffi_linux_x64.tar.gz +0 -0
  14. package/build/qemu/2.0.1/koffi_openbsd_ia32.tar.gz +0 -0
  15. package/build/qemu/2.0.1/koffi_openbsd_x64.tar.gz +0 -0
  16. package/build/qemu/2.0.1/koffi_win32_arm64.tar.gz +0 -0
  17. package/build/qemu/2.0.1/koffi_win32_ia32.tar.gz +0 -0
  18. package/build/qemu/2.0.1/koffi_win32_x64.tar.gz +0 -0
  19. package/doc/changes.md +156 -1
  20. package/doc/conf.py +14 -1
  21. package/doc/contribute.md +0 -1
  22. package/doc/dist/doctrees/benchmarks.doctree +0 -0
  23. package/doc/dist/doctrees/changes.doctree +0 -0
  24. package/doc/dist/doctrees/environment.pickle +0 -0
  25. package/doc/dist/doctrees/functions.doctree +0 -0
  26. package/doc/dist/doctrees/index.doctree +0 -0
  27. package/doc/dist/doctrees/types.doctree +0 -0
  28. package/doc/dist/html/.buildinfo +1 -1
  29. package/doc/dist/html/_sources/benchmarks.md.txt +2 -2
  30. package/doc/dist/html/_sources/changes.md.txt +156 -1
  31. package/doc/dist/html/_sources/functions.md.txt +14 -10
  32. package/doc/dist/html/_sources/types.md.txt +18 -1
  33. package/doc/dist/html/benchmarks.html +7 -3
  34. package/doc/dist/html/changes.html +230 -14
  35. package/doc/dist/html/contribute.html +5 -1
  36. package/doc/dist/html/functions.html +25 -18
  37. package/doc/dist/html/genindex.html +5 -1
  38. package/doc/dist/html/index.html +13 -19
  39. package/doc/dist/html/memory.html +7 -3
  40. package/doc/dist/html/objects.inv +0 -0
  41. package/doc/dist/html/platforms.html +6 -2
  42. package/doc/dist/html/search.html +5 -1
  43. package/doc/dist/html/searchindex.js +1 -1
  44. package/doc/dist/html/start.html +5 -1
  45. package/doc/dist/html/types.html +28 -4
  46. package/doc/functions.md +138 -14
  47. package/doc/templates/badges.html +5 -0
  48. package/doc/types.md +45 -12
  49. package/package.json +9 -7
  50. package/qemu/registry/machines.json +5 -5
  51. package/qemu/registry/sha256sum.txt +16 -16
  52. package/src/abi_arm32.cc +91 -19
  53. package/src/abi_arm32_fwd.S +121 -57
  54. package/src/abi_arm64.cc +91 -19
  55. package/src/abi_arm64_fwd.S +96 -0
  56. package/src/abi_arm64_fwd.asm +128 -0
  57. package/src/abi_riscv64.cc +89 -19
  58. package/src/abi_riscv64_fwd.S +96 -0
  59. package/src/abi_x64_sysv.cc +94 -22
  60. package/src/abi_x64_sysv_fwd.S +96 -0
  61. package/src/abi_x64_win.cc +89 -19
  62. package/src/abi_x64_win_fwd.asm +128 -0
  63. package/src/abi_x86.cc +94 -19
  64. package/src/abi_x86_fwd.S +96 -0
  65. package/src/abi_x86_fwd.asm +128 -0
  66. package/src/call.cc +97 -63
  67. package/src/call.hh +2 -1
  68. package/src/ffi.cc +453 -141
  69. package/src/ffi.hh +23 -9
  70. package/src/parser.cc +18 -41
  71. package/src/util.cc +117 -27
  72. package/src/util.hh +3 -2
  73. package/test/callbacks.js +54 -8
  74. package/test/misc.c +29 -14
  75. package/test/raylib.js +1 -1
  76. package/test/sqlite.js +25 -17
  77. package/test/sync.js +44 -32
  78. package/vendor/libcc/libcc.cc +18 -5
  79. package/vendor/libcc/libcc.hh +70 -23
  80. package/build/qemu/1.3.11/koffi_darwin_arm64.tar.gz +0 -0
  81. package/build/qemu/1.3.11/koffi_darwin_x64.tar.gz +0 -0
  82. package/build/qemu/1.3.11/koffi_freebsd_arm64.tar.gz +0 -0
  83. package/build/qemu/1.3.11/koffi_freebsd_ia32.tar.gz +0 -0
  84. package/build/qemu/1.3.11/koffi_freebsd_x64.tar.gz +0 -0
  85. package/build/qemu/1.3.11/koffi_linux_arm32hf.tar.gz +0 -0
  86. package/build/qemu/1.3.11/koffi_linux_arm64.tar.gz +0 -0
  87. package/build/qemu/1.3.11/koffi_linux_ia32.tar.gz +0 -0
  88. package/build/qemu/1.3.11/koffi_linux_riscv64hf64.tar.gz +0 -0
  89. package/build/qemu/1.3.11/koffi_linux_x64.tar.gz +0 -0
  90. package/build/qemu/1.3.11/koffi_openbsd_ia32.tar.gz +0 -0
  91. package/build/qemu/1.3.11/koffi_openbsd_x64.tar.gz +0 -0
  92. package/build/qemu/1.3.11/koffi_win32_arm64.tar.gz +0 -0
  93. package/build/qemu/1.3.11/koffi_win32_ia32.tar.gz +0 -0
  94. package/build/qemu/1.3.11/koffi_win32_x64.tar.gz +0 -0
@@ -74,6 +74,22 @@ extern "C" int Trampoline12; extern "C" int TrampolineX12;
74
74
  extern "C" int Trampoline13; extern "C" int TrampolineX13;
75
75
  extern "C" int Trampoline14; extern "C" int TrampolineX14;
76
76
  extern "C" int Trampoline15; extern "C" int TrampolineX15;
77
+ extern "C" int Trampoline16; extern "C" int TrampolineX16;
78
+ extern "C" int Trampoline17; extern "C" int TrampolineX17;
79
+ extern "C" int Trampoline18; extern "C" int TrampolineX18;
80
+ extern "C" int Trampoline19; extern "C" int TrampolineX19;
81
+ extern "C" int Trampoline20; extern "C" int TrampolineX20;
82
+ extern "C" int Trampoline21; extern "C" int TrampolineX21;
83
+ extern "C" int Trampoline22; extern "C" int TrampolineX22;
84
+ extern "C" int Trampoline23; extern "C" int TrampolineX23;
85
+ extern "C" int Trampoline24; extern "C" int TrampolineX24;
86
+ extern "C" int Trampoline25; extern "C" int TrampolineX25;
87
+ extern "C" int Trampoline26; extern "C" int TrampolineX26;
88
+ extern "C" int Trampoline27; extern "C" int TrampolineX27;
89
+ extern "C" int Trampoline28; extern "C" int TrampolineX28;
90
+ extern "C" int Trampoline29; extern "C" int TrampolineX29;
91
+ extern "C" int Trampoline30; extern "C" int TrampolineX30;
92
+ extern "C" int Trampoline31; extern "C" int TrampolineX31;
77
93
 
78
94
  extern "C" napi_value CallSwitchStack(Napi::Function *func, size_t argc, napi_value *argv,
79
95
  uint8_t *old_sp, Span<uint8_t> *new_stack,
@@ -95,9 +111,25 @@ static void *const Trampolines[][2] = {
95
111
  { &Trampoline12, &TrampolineX12 },
96
112
  { &Trampoline13, &TrampolineX13 },
97
113
  { &Trampoline14, &TrampolineX14 },
98
- { &Trampoline15, &TrampolineX15 }
114
+ { &Trampoline15, &TrampolineX15 },
115
+ { &Trampoline16, &TrampolineX16 },
116
+ { &Trampoline17, &TrampolineX17 },
117
+ { &Trampoline18, &TrampolineX18 },
118
+ { &Trampoline19, &TrampolineX19 },
119
+ { &Trampoline20, &TrampolineX20 },
120
+ { &Trampoline21, &TrampolineX21 },
121
+ { &Trampoline22, &TrampolineX22 },
122
+ { &Trampoline23, &TrampolineX23 },
123
+ { &Trampoline24, &TrampolineX24 },
124
+ { &Trampoline25, &TrampolineX25 },
125
+ { &Trampoline26, &TrampolineX26 },
126
+ { &Trampoline27, &TrampolineX27 },
127
+ { &Trampoline28, &TrampolineX28 },
128
+ { &Trampoline29, &TrampolineX29 },
129
+ { &Trampoline30, &TrampolineX30 },
130
+ { &Trampoline31, &TrampolineX31 }
99
131
  };
100
- RG_STATIC_ASSERT(RG_LEN(Trampolines) == MaxTrampolines);
132
+ RG_STATIC_ASSERT(RG_LEN(Trampolines) == MaxTrampolines * 2);
101
133
 
102
134
  static RG_THREAD_LOCAL CallData *exec_call;
103
135
 
@@ -354,10 +386,10 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
354
386
  if (value.IsFunction()) {
355
387
  Napi::Function func = value.As<Napi::Function>();
356
388
 
357
- ptr = ReserveTrampoline(param.type->proto, func);
389
+ ptr = ReserveTrampoline(param.type->ref.proto, func);
358
390
  if (RG_UNLIKELY(!ptr))
359
391
  return false;
360
- } else if (CheckValueTag(instance, value, param.type)) {
392
+ } else if (CheckValueTag(instance, value, param.type->ref.marker)) {
361
393
  ptr = value.As<Napi::External<void>>().Data();
362
394
  } else if (IsNullOrUndefined(value)) {
363
395
  ptr = nullptr;
@@ -368,6 +400,8 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
368
400
 
369
401
  *(void **)((param.gpr_count ? gpr_ptr : args_ptr)++) = ptr;
370
402
  } break;
403
+
404
+ case PrimitiveKind::Prototype: { RG_UNREACHABLE(); } break;
371
405
  }
372
406
  }
373
407
 
@@ -421,6 +455,8 @@ void CallData::Execute()
421
455
  case PrimitiveKind::Array: { RG_UNREACHABLE(); } break;
422
456
  case PrimitiveKind::Float32: { result.f = PERFORM_CALL(F); } break;
423
457
  case PrimitiveKind::Float64: { result.d = PERFORM_CALL(DD).fa0; } break;
458
+
459
+ case PrimitiveKind::Prototype: { RG_UNREACHABLE(); } break;
424
460
  }
425
461
 
426
462
  #undef PERFORM_CALL
@@ -428,10 +464,16 @@ void CallData::Execute()
428
464
 
429
465
  Napi::Value CallData::Complete()
430
466
  {
431
- PopOutArguments();
467
+ RG_DEFER {
468
+ PopOutArguments();
469
+
470
+ if (func->ret.type->dispose) {
471
+ func->ret.type->dispose(env, func->ret.type, result.ptr);
472
+ }
473
+ };
432
474
 
433
475
  switch (func->ret.type->primitive) {
434
- case PrimitiveKind::Void: return env.Null();
476
+ case PrimitiveKind::Void: return env.Undefined();
435
477
  case PrimitiveKind::Bool: return Napi::Boolean::New(env, result.u32);
436
478
  case PrimitiveKind::Int8: return Napi::Number::New(env, (double)result.i8);
437
479
  case PrimitiveKind::UInt8: return Napi::Number::New(env, (double)result.u8);
@@ -447,7 +489,7 @@ Napi::Value CallData::Complete()
447
489
  case PrimitiveKind::Callback: {
448
490
  if (result.ptr) {
449
491
  Napi::External<void> external = Napi::External<void>::New(env, result.ptr);
450
- SetValueTag(instance, external, func->ret.type);
492
+ SetValueTag(instance, external, func->ret.type->ref.marker);
451
493
 
452
494
  return external;
453
495
  } else {
@@ -469,6 +511,8 @@ Napi::Value CallData::Complete()
469
511
  case PrimitiveKind::Array: { RG_UNREACHABLE(); } break;
470
512
  case PrimitiveKind::Float32: return Napi::Number::New(env, (double)result.f);
471
513
  case PrimitiveKind::Float64: return Napi::Number::New(env, result.d);
514
+
515
+ case PrimitiveKind::Prototype: { RG_UNREACHABLE(); } break;
472
516
  }
473
517
 
474
518
  RG_UNREACHABLE();
@@ -476,12 +520,10 @@ Napi::Value CallData::Complete()
476
520
 
477
521
  void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
478
522
  {
479
- const TrampolineInfo &trampoline = instance->trampolines[idx];
480
-
481
- if (RG_UNLIKELY(trampoline.generation != mem->generation)) {
482
- ThrowError<Napi::Error>(env, "Cannot use non-persistent callback beyond FFI call");
523
+ if (RG_UNLIKELY(env.IsExceptionPending()))
483
524
  return;
484
- }
525
+
526
+ const TrampolineInfo &trampoline = instance->trampolines[idx];
485
527
 
486
528
  const FunctionInfo *proto = trampoline.proto;
487
529
  Napi::Function func = trampoline.func.Value();
@@ -493,6 +535,13 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
493
535
  uint8_t *return_ptr = proto->ret.use_memory ? (uint8_t *)gpr_ptr[0] : nullptr;
494
536
  gpr_ptr += proto->ret.use_memory;
495
537
 
538
+ RG_DEFER_N(err_guard) { memset(out_reg, 0, RG_SIZE(*out_reg)); };
539
+
540
+ if (RG_UNLIKELY(trampoline.generation >= 0 && trampoline.generation != (int32_t)mem->generation)) {
541
+ ThrowError<Napi::Error>(env, "Cannot use non-registered callback beyond FFI call");
542
+ return;
543
+ }
544
+
496
545
  LocalArray<napi_value, MaxParameters> arguments;
497
546
 
498
547
  // Convert to JS arguments
@@ -562,12 +611,20 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
562
611
 
563
612
  Napi::Value arg = str ? Napi::String::New(env, str) : env.Null();
564
613
  arguments.Append(arg);
614
+
615
+ if (param.type->dispose) {
616
+ param.type->dispose(env, param.type, str);
617
+ }
565
618
  } break;
566
619
  case PrimitiveKind::String16: {
567
620
  const char16_t *str16 = *(const char16_t **)((param.gpr_count ? gpr_ptr : args_ptr)++);
568
621
 
569
622
  Napi::Value arg = str16 ? Napi::String::New(env, str16) : env.Null();
570
623
  arguments.Append(arg);
624
+
625
+ if (param.type->dispose) {
626
+ param.type->dispose(env, param.type, str16);
627
+ }
571
628
  } break;
572
629
  case PrimitiveKind::Pointer:
573
630
  case PrimitiveKind::Callback: {
@@ -575,12 +632,16 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
575
632
 
576
633
  if (ptr2) {
577
634
  Napi::External<void> external = Napi::External<void>::New(env, ptr2);
578
- SetValueTag(instance, external, param.type);
635
+ SetValueTag(instance, external, param.type->ref.marker);
579
636
 
580
637
  arguments.Append(external);
581
638
  } else {
582
639
  arguments.Append(env.Null());
583
640
  }
641
+
642
+ if (param.type->dispose) {
643
+ param.type->dispose(env, param.type, ptr2);
644
+ }
584
645
  } break;
585
646
  case PrimitiveKind::Record: {
586
647
  if (!param.use_memory) {
@@ -640,6 +701,8 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
640
701
  Napi::Value arg = Napi::Number::New(env, d);
641
702
  arguments.Append(arg);
642
703
  } break;
704
+
705
+ case PrimitiveKind::Prototype: { RG_UNREACHABLE(); } break;
643
706
  }
644
707
  }
645
708
 
@@ -650,6 +713,9 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
650
713
  [](Napi::Function *func, size_t argc, napi_value *argv) { return (napi_value)func->Call(argc, argv); });
651
714
  Napi::Value value(env, ret);
652
715
 
716
+ if (RG_UNLIKELY(env.IsExceptionPending()))
717
+ return;
718
+
653
719
  // Convert the result
654
720
  switch (type->primitive) {
655
721
  case PrimitiveKind::Void: {} break;
@@ -711,14 +777,14 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
711
777
  case PrimitiveKind::Pointer: {
712
778
  uint8_t *ptr;
713
779
 
714
- if (CheckValueTag(instance, value, type)) {
780
+ if (CheckValueTag(instance, value, type->ref.marker)) {
715
781
  ptr = value.As<Napi::External<uint8_t>>().Data();
716
- } else if (IsObject(value) && type->ref->primitive == PrimitiveKind::Record) {
782
+ } else if (IsObject(value) && type->ref.type->primitive == PrimitiveKind::Record) {
717
783
  Napi::Object obj = value.As<Napi::Object>();
718
784
 
719
- ptr = AllocHeap(type->ref->size, 16);
785
+ ptr = AllocHeap(type->ref.type->size, 16);
720
786
 
721
- if (!PushObject(obj, type->ref, ptr))
787
+ if (!PushObject(obj, type->ref.type, ptr))
722
788
  return;
723
789
  } else if (IsNullOrUndefined(value)) {
724
790
  ptr = nullptr;
@@ -773,10 +839,10 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
773
839
  if (value.IsFunction()) {
774
840
  Napi::Function func2 = value.As<Napi::Function>();
775
841
 
776
- ptr = ReserveTrampoline(type->proto, func2);
842
+ ptr = ReserveTrampoline(type->ref.proto, func2);
777
843
  if (RG_UNLIKELY(!ptr))
778
844
  return;
779
- } else if (CheckValueTag(instance, value, type)) {
845
+ } else if (CheckValueTag(instance, value, type->ref.marker)) {
780
846
  ptr = value.As<Napi::External<uint8_t>>().Data();
781
847
  } else if (IsNullOrUndefined(value)) {
782
848
  ptr = nullptr;
@@ -787,7 +853,11 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
787
853
 
788
854
  out_reg->a0 = (uint64_t)ptr;
789
855
  } break;
856
+
857
+ case PrimitiveKind::Prototype: { RG_UNREACHABLE(); } break;
790
858
  }
859
+
860
+ err_guard.Disable();
791
861
  }
792
862
 
793
863
  void *GetTrampoline(Size idx, const FunctionInfo *proto)
@@ -152,6 +152,22 @@ ForwardCallXDD:
152
152
  .global Trampoline13
153
153
  .global Trampoline14
154
154
  .global Trampoline15
155
+ .global Trampoline16
156
+ .global Trampoline17
157
+ .global Trampoline18
158
+ .global Trampoline19
159
+ .global Trampoline20
160
+ .global Trampoline21
161
+ .global Trampoline22
162
+ .global Trampoline23
163
+ .global Trampoline24
164
+ .global Trampoline25
165
+ .global Trampoline26
166
+ .global Trampoline27
167
+ .global Trampoline28
168
+ .global Trampoline29
169
+ .global Trampoline30
170
+ .global Trampoline31
155
171
  .global TrampolineX0
156
172
  .global TrampolineX1
157
173
  .global TrampolineX2
@@ -168,6 +184,22 @@ ForwardCallXDD:
168
184
  .global TrampolineX13
169
185
  .global TrampolineX14
170
186
  .global TrampolineX15
187
+ .global TrampolineX16
188
+ .global TrampolineX17
189
+ .global TrampolineX18
190
+ .global TrampolineX19
191
+ .global TrampolineX20
192
+ .global TrampolineX21
193
+ .global TrampolineX22
194
+ .global TrampolineX23
195
+ .global TrampolineX24
196
+ .global TrampolineX25
197
+ .global TrampolineX26
198
+ .global TrampolineX27
199
+ .global TrampolineX28
200
+ .global TrampolineX29
201
+ .global TrampolineX30
202
+ .global TrampolineX31
171
203
  .global RelayCallback
172
204
  .global CallSwitchStack
173
205
 
@@ -265,6 +297,38 @@ Trampoline14:
265
297
  trampoline 14
266
298
  Trampoline15:
267
299
  trampoline 15
300
+ Trampoline16:
301
+ trampoline 16
302
+ Trampoline17:
303
+ trampoline 17
304
+ Trampoline18:
305
+ trampoline 18
306
+ Trampoline19:
307
+ trampoline 19
308
+ Trampoline20:
309
+ trampoline 20
310
+ Trampoline21:
311
+ trampoline 21
312
+ Trampoline22:
313
+ trampoline 22
314
+ Trampoline23:
315
+ trampoline 23
316
+ Trampoline24:
317
+ trampoline 24
318
+ Trampoline25:
319
+ trampoline 25
320
+ Trampoline26:
321
+ trampoline 26
322
+ Trampoline27:
323
+ trampoline 27
324
+ Trampoline28:
325
+ trampoline 28
326
+ Trampoline29:
327
+ trampoline 29
328
+ Trampoline30:
329
+ trampoline 30
330
+ Trampoline31:
331
+ trampoline 31
268
332
 
269
333
  TrampolineX0:
270
334
  trampoline_vec 0
@@ -298,6 +362,38 @@ TrampolineX14:
298
362
  trampoline_vec 14
299
363
  TrampolineX15:
300
364
  trampoline_vec 15
365
+ TrampolineX16:
366
+ trampoline_vec 16
367
+ TrampolineX17:
368
+ trampoline_vec 17
369
+ TrampolineX18:
370
+ trampoline_vec 18
371
+ TrampolineX19:
372
+ trampoline_vec 19
373
+ TrampolineX20:
374
+ trampoline_vec 20
375
+ TrampolineX21:
376
+ trampoline_vec 21
377
+ TrampolineX22:
378
+ trampoline_vec 22
379
+ TrampolineX23:
380
+ trampoline_vec 23
381
+ TrampolineX24:
382
+ trampoline_vec 24
383
+ TrampolineX25:
384
+ trampoline_vec 25
385
+ TrampolineX26:
386
+ trampoline_vec 26
387
+ TrampolineX27:
388
+ trampoline_vec 27
389
+ TrampolineX28:
390
+ trampoline_vec 28
391
+ TrampolineX29:
392
+ trampoline_vec 29
393
+ TrampolineX30:
394
+ trampoline_vec 30
395
+ TrampolineX31:
396
+ trampoline_vec 31
301
397
 
302
398
  # When a callback is relayed, Koffi will call into Node.js and V8 to execute Javascript.
303
399
  # The problem is that we're still running on the separate Koffi stack, and V8 will
@@ -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)