koffi 2.2.1 → 2.2.2-beta.2

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 (74) hide show
  1. package/package.json +1 -1
  2. package/src/koffi/build/2.2.2-beta.2/koffi_darwin_arm64.tar.gz +0 -0
  3. package/src/koffi/build/2.2.2-beta.2/koffi_darwin_x64.tar.gz +0 -0
  4. package/src/koffi/build/2.2.2-beta.2/koffi_freebsd_arm64.tar.gz +0 -0
  5. package/src/koffi/build/2.2.2-beta.2/koffi_freebsd_ia32.tar.gz +0 -0
  6. package/src/koffi/build/2.2.2-beta.2/koffi_freebsd_x64.tar.gz +0 -0
  7. package/src/koffi/build/2.2.2-beta.2/koffi_linux_arm32hf.tar.gz +0 -0
  8. package/src/koffi/build/2.2.2-beta.2/koffi_linux_arm64.tar.gz +0 -0
  9. package/src/koffi/build/2.2.2-beta.2/koffi_linux_ia32.tar.gz +0 -0
  10. package/src/koffi/build/2.2.2-beta.2/koffi_linux_riscv64hf64.tar.gz +0 -0
  11. package/src/koffi/build/2.2.2-beta.2/koffi_linux_x64.tar.gz +0 -0
  12. package/src/koffi/build/2.2.2-beta.2/koffi_openbsd_ia32.tar.gz +0 -0
  13. package/src/koffi/build/2.2.2-beta.2/koffi_openbsd_x64.tar.gz +0 -0
  14. package/src/koffi/build/2.2.2-beta.2/koffi_win32_arm64.tar.gz +0 -0
  15. package/src/koffi/build/2.2.2-beta.2/koffi_win32_ia32.tar.gz +0 -0
  16. package/src/koffi/build/2.2.2-beta.2/koffi_win32_x64.tar.gz +0 -0
  17. package/src/koffi/qemu/qemu.js +12 -10
  18. package/src/koffi/src/abi_arm32.cc +7 -12
  19. package/src/koffi/src/abi_arm64.cc +7 -12
  20. package/src/koffi/src/abi_riscv64.cc +7 -12
  21. package/src/koffi/src/abi_x64_sysv.cc +7 -12
  22. package/src/koffi/src/abi_x64_win.cc +7 -12
  23. package/src/koffi/src/abi_x86.cc +7 -12
  24. package/src/koffi/src/call.cc +51 -2
  25. package/src/koffi/src/call.hh +6 -1
  26. package/src/koffi/src/ffi.cc +61 -7
  27. package/src/koffi/src/ffi.hh +2 -0
  28. package/src/koffi/src/index.js +7 -2
  29. package/src/koffi/test/CMakeLists.txt +1 -1
  30. package/src/koffi/test/async.js +3 -0
  31. package/src/koffi/test/callbacks.js +11 -0
  32. package/vendor/{sqlite3mc → sqlite3}/sqlite3.c +139 -43
  33. package/vendor/{sqlite3mc → sqlite3}/sqlite3.h +10 -3
  34. package/vendor/{sqlite3mc → sqlite3}/sqlite3ext.h +0 -0
  35. package/vendor/{sqlite3mc → sqlite3}/sqlite3mc.c +156 -53
  36. package/vendor/{sqlite3mc → sqlite3}/sqlite3mc.def +0 -0
  37. package/vendor/{sqlite3mc → sqlite3}/sqlite3mc.h +12 -5
  38. package/vendor/sqlite3/wasm/README.txt +23 -0
  39. package/vendor/sqlite3/wasm/common/SqliteTestUtil.js +236 -0
  40. package/vendor/sqlite3/wasm/common/emscripten.css +24 -0
  41. package/vendor/sqlite3/wasm/common/testing.css +63 -0
  42. package/vendor/sqlite3/wasm/demo-123-worker.html +44 -0
  43. package/vendor/sqlite3/wasm/demo-123.html +24 -0
  44. package/vendor/sqlite3/wasm/demo-123.js +289 -0
  45. package/vendor/sqlite3/wasm/demo-jsstorage.html +49 -0
  46. package/vendor/sqlite3/wasm/demo-jsstorage.js +114 -0
  47. package/vendor/sqlite3/wasm/demo-worker1-promiser.html +34 -0
  48. package/vendor/sqlite3/wasm/demo-worker1-promiser.js +270 -0
  49. package/vendor/sqlite3/wasm/demo-worker1.html +34 -0
  50. package/vendor/sqlite3/wasm/demo-worker1.js +345 -0
  51. package/vendor/sqlite3/wasm/index.html +90 -0
  52. package/vendor/sqlite3/wasm/jswasm/sqlite3-opfs-async-proxy.js +830 -0
  53. package/vendor/sqlite3/wasm/jswasm/sqlite3-worker1-promiser.js +259 -0
  54. package/vendor/sqlite3/wasm/jswasm/sqlite3-worker1.js +49 -0
  55. package/vendor/sqlite3/wasm/jswasm/sqlite3.js +10119 -0
  56. package/vendor/sqlite3/wasm/jswasm/sqlite3.wasm +0 -0
  57. package/vendor/sqlite3/wasm/tester1-worker.html +63 -0
  58. package/vendor/sqlite3/wasm/tester1.html +28 -0
  59. package/vendor/sqlite3/wasm/tester1.js +1864 -0
  60. package/src/koffi/build/2.2.1/koffi_darwin_arm64.tar.gz +0 -0
  61. package/src/koffi/build/2.2.1/koffi_darwin_x64.tar.gz +0 -0
  62. package/src/koffi/build/2.2.1/koffi_freebsd_arm64.tar.gz +0 -0
  63. package/src/koffi/build/2.2.1/koffi_freebsd_ia32.tar.gz +0 -0
  64. package/src/koffi/build/2.2.1/koffi_freebsd_x64.tar.gz +0 -0
  65. package/src/koffi/build/2.2.1/koffi_linux_arm32hf.tar.gz +0 -0
  66. package/src/koffi/build/2.2.1/koffi_linux_arm64.tar.gz +0 -0
  67. package/src/koffi/build/2.2.1/koffi_linux_ia32.tar.gz +0 -0
  68. package/src/koffi/build/2.2.1/koffi_linux_riscv64hf64.tar.gz +0 -0
  69. package/src/koffi/build/2.2.1/koffi_linux_x64.tar.gz +0 -0
  70. package/src/koffi/build/2.2.1/koffi_openbsd_ia32.tar.gz +0 -0
  71. package/src/koffi/build/2.2.1/koffi_openbsd_x64.tar.gz +0 -0
  72. package/src/koffi/build/2.2.1/koffi_win32_arm64.tar.gz +0 -0
  73. package/src/koffi/build/2.2.1/koffi_win32_ia32.tar.gz +0 -0
  74. package/src/koffi/build/2.2.1/koffi_win32_x64.tar.gz +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "koffi",
3
- "version": "2.2.1",
3
+ "version": "2.2.2-beta.2",
4
4
  "stable": "2.2.1",
5
5
  "description": "Fast and simple C FFI (foreign function interface) for Node.js",
6
6
  "keywords": [
@@ -63,6 +63,7 @@ async function main() {
63
63
  switch (process.argv[2]) {
64
64
  case 'pack': { command = pack; } break;
65
65
  case 'publish': { command = publish; } break;
66
+ case 'prepare': { command = prepare; } break;
66
67
  case 'test': { command = test; } break;
67
68
  case 'start': { command = start; } break;
68
69
  case 'stop': { command = stop; } break;
@@ -190,7 +191,7 @@ async function main() {
190
191
  console.log();
191
192
 
192
193
  try {
193
- let success = await command();
194
+ let success = !!(await command());
194
195
  process.exit(!success);
195
196
  } catch (err) {
196
197
  console.error(err);
@@ -205,6 +206,7 @@ Commands:
205
206
  test Run the machines and perform the tests (default)
206
207
  pack Create NPM package with prebuilt Koffi binaries
207
208
  publish Publish NPM package with prebuilt Koffi binaries
209
+ prepare Prepare distribution-ready NPM package directory
208
210
 
209
211
  start Start the machines but don't run anythingh
210
212
  stop Stop running machines
@@ -290,10 +292,9 @@ async function start(detach = true) {
290
292
 
291
293
  async function pack() {
292
294
  let pack_dir = script_dir + '/../build';
293
- let dist_dir = script_dir + '/../build/dist';
295
+ let dist_dir = await prepare(dist_dir);
294
296
 
295
- let success = await prepare(dist_dir);
296
- if (!success)
297
+ if (dist_dir == null)
297
298
  return false;
298
299
 
299
300
  let npm = (process.platform == 'win32') ? 'npm.cmd' : 'npm';
@@ -305,10 +306,9 @@ async function pack() {
305
306
  }
306
307
 
307
308
  async function publish() {
308
- let dist_dir = script_dir + '/../build/dist';
309
+ let dist_dir = await prepare();
309
310
 
310
- let success = await prepare(dist_dir);
311
- if (!success)
311
+ if (dist_dir == null)
312
312
  return false;
313
313
 
314
314
  let npm = (process.platform == 'win32') ? 'npm.cmd' : 'npm';
@@ -319,7 +319,8 @@ async function publish() {
319
319
  });
320
320
  }
321
321
 
322
- async function prepare(dist_dir) {
322
+ async function prepare() {
323
+ let dist_dir = script_dir + '/../build/dist';
323
324
  let snapshot_dir = snapshot();
324
325
 
325
326
  let json = fs.readFileSync(root_dir + '/src/koffi/package.json', { encoding: 'utf-8' });
@@ -457,7 +458,7 @@ async function prepare(dist_dir) {
457
458
  if (!success) {
458
459
  console.log('');
459
460
  console.log('>> Status: ' + chalk.bold.red('FAILED'));
460
- return false;
461
+ return null;
461
462
  }
462
463
  }
463
464
 
@@ -495,7 +496,7 @@ async function prepare(dist_dir) {
495
496
  fs.renameSync(dist_dir + '/web/koffi.dev', dist_dir + '/doc');
496
497
  }
497
498
 
498
- return true;
499
+ return dist_dir;
499
500
  }
500
501
 
501
502
  function snapshot() {
@@ -519,6 +520,7 @@ function snapshot() {
519
520
  parts[1] == 'miniz' ||
520
521
  parts[1] == 'node-addon-api' ||
521
522
  parts[1] == 'raylib' ||
523
+ parts[1] == 'sqlite3' ||
522
524
  parts[1] == 'sqlite3mc';
523
525
  } else if (parts[0] == 'web') {
524
526
  return parts[1] == null || parts[1] == 'koffi.dev';
@@ -121,8 +121,6 @@ static void *const Trampolines[][2] = {
121
121
  };
122
122
  RG_STATIC_ASSERT(RG_LEN(Trampolines) == MaxTrampolines * 2);
123
123
 
124
- static RG_THREAD_LOCAL CallData *exec_call;
125
-
126
124
  static inline int IsHFA(const TypeInfo *type)
127
125
  {
128
126
  #ifdef __ARM_PCS_VFP
@@ -495,9 +493,6 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
495
493
 
496
494
  void CallData::Execute()
497
495
  {
498
- RG_DEFER_C(prev_call = exec_call) { exec_call = prev_call; };
499
- exec_call = this;
500
-
501
496
  #define PERFORM_CALL(Suffix) \
502
497
  ([&]() { \
503
498
  auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, new_sp, &old_sp) \
@@ -863,8 +858,13 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
863
858
  const TypeInfo *type = proto->ret.type;
864
859
 
865
860
  // Make the call
866
- napi_value ret = CallSwitchStack(&func, (size_t)arguments.len, arguments.data, old_sp, &mem->stack,
867
- [](Napi::Function *func, size_t argc, napi_value *argv) { return (napi_value)func->Call(argv[0], argc - 1, argv + 1); });
861
+ napi_value ret;
862
+ if (async) {
863
+ ret = (napi_value)func.Call(arguments[0], arguments.len - 1, arguments.data + 1);
864
+ } else {
865
+ ret = CallSwitchStack(&func, (size_t)arguments.len, arguments.data, old_sp, &mem->stack,
866
+ [](Napi::Function *func, size_t argc, napi_value *argv) { return (napi_value)func->Call(argv[0], argc - 1, argv + 1); });
867
+ }
868
868
  Napi::Value value(env, ret);
869
869
 
870
870
  if (RG_UNLIKELY(env.IsExceptionPending()))
@@ -1059,11 +1059,6 @@ void *GetTrampoline(Size idx, const FunctionInfo *proto)
1059
1059
  return Trampolines[idx][vec];
1060
1060
  }
1061
1061
 
1062
- extern "C" void RelayCallback(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
1063
- {
1064
- exec_call->Relay(idx, own_sp, caller_sp, out_reg);
1065
- }
1066
-
1067
1062
  }
1068
1063
 
1069
1064
  #endif
@@ -123,8 +123,6 @@ static void *const Trampolines[][2] = {
123
123
  };
124
124
  RG_STATIC_ASSERT(RG_LEN(Trampolines) == MaxTrampolines * 2);
125
125
 
126
- static RG_THREAD_LOCAL CallData *exec_call;
127
-
128
126
  static inline int IsHFA(const TypeInfo *type)
129
127
  {
130
128
  return IsHFA(type, 1, 4);
@@ -563,9 +561,6 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
563
561
 
564
562
  void CallData::Execute()
565
563
  {
566
- RG_DEFER_C(prev_call = exec_call) { exec_call = prev_call; };
567
- exec_call = this;
568
-
569
564
  #define PERFORM_CALL(Suffix) \
570
565
  ([&]() { \
571
566
  auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, new_sp, &old_sp) \
@@ -1088,8 +1083,13 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
1088
1083
  const TypeInfo *type = proto->ret.type;
1089
1084
 
1090
1085
  // Make the call
1091
- napi_value ret = CallSwitchStack(&func, (size_t)arguments.len, arguments.data, old_sp, &mem->stack,
1092
- [](Napi::Function *func, size_t argc, napi_value *argv) { return (napi_value)func->Call(argv[0], argc - 1, argv + 1); });
1086
+ napi_value ret;
1087
+ if (async) {
1088
+ ret = (napi_value)func.Call(arguments[0], arguments.len - 1, arguments.data + 1);
1089
+ } else {
1090
+ ret = CallSwitchStack(&func, (size_t)arguments.len, arguments.data, old_sp, &mem->stack,
1091
+ [](Napi::Function *func, size_t argc, napi_value *argv) { return (napi_value)func->Call(argv[0], argc - 1, argv + 1); });
1092
+ }
1093
1093
  Napi::Value value(env, ret);
1094
1094
 
1095
1095
  if (RG_UNLIKELY(env.IsExceptionPending()))
@@ -1252,11 +1252,6 @@ void *GetTrampoline(Size idx, const FunctionInfo *proto)
1252
1252
  return Trampolines[idx][vec];
1253
1253
  }
1254
1254
 
1255
- extern "C" void RelayCallback(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
1256
- {
1257
- exec_call->Relay(idx, own_sp, caller_sp, out_reg);
1258
- }
1259
-
1260
1255
  }
1261
1256
 
1262
1257
  #endif
@@ -131,8 +131,6 @@ static void *const Trampolines[][2] = {
131
131
  };
132
132
  RG_STATIC_ASSERT(RG_LEN(Trampolines) == MaxTrampolines * 2);
133
133
 
134
- static RG_THREAD_LOCAL CallData *exec_call;
135
-
136
134
  static void AnalyseParameter(ParameterInfo *param, int gpr_avail, int vec_avail)
137
135
  {
138
136
  gpr_avail = std::min(2, gpr_avail);
@@ -410,9 +408,6 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
410
408
 
411
409
  void CallData::Execute()
412
410
  {
413
- RG_DEFER_C(prev_call = exec_call) { exec_call = prev_call; };
414
- exec_call = this;
415
-
416
411
  #define PERFORM_CALL(Suffix) \
417
412
  ([&]() { \
418
413
  auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, new_sp, &old_sp) \
@@ -762,8 +757,13 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
762
757
  const TypeInfo *type = proto->ret.type;
763
758
 
764
759
  // Make the call
765
- napi_value ret = CallSwitchStack(&func, (size_t)arguments.len, arguments.data, old_sp, &mem->stack,
766
- [](Napi::Function *func, size_t argc, napi_value *argv) { return (napi_value)func->Call(argv[0], argc - 1, argv + 1); });
760
+ napi_value ret;
761
+ if (async) {
762
+ ret = (napi_value)func.Call(arguments[0], arguments.len - 1, arguments.data + 1);
763
+ } else {
764
+ ret = CallSwitchStack(&func, (size_t)arguments.len, arguments.data, old_sp, &mem->stack,
765
+ [](Napi::Function *func, size_t argc, napi_value *argv) { return (napi_value)func->Call(argv[0], argc - 1, argv + 1); });
766
+ }
767
767
  Napi::Value value(env, ret);
768
768
 
769
769
  if (RG_UNLIKELY(env.IsExceptionPending()))
@@ -925,11 +925,6 @@ void *GetTrampoline(Size idx, const FunctionInfo *proto)
925
925
  return Trampolines[idx][fp];
926
926
  }
927
927
 
928
- extern "C" void RelayCallback(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
929
- {
930
- exec_call->Relay(idx, own_sp, caller_sp, out_reg);
931
- }
932
-
933
928
  }
934
929
 
935
930
  #endif
@@ -138,8 +138,6 @@ static void *const Trampolines[][2] = {
138
138
  };
139
139
  RG_STATIC_ASSERT(RG_LEN(Trampolines) == MaxTrampolines * 2);
140
140
 
141
- static RG_THREAD_LOCAL CallData *exec_call;
142
-
143
141
  static inline RegisterClass MergeClasses(RegisterClass cls1, RegisterClass cls2)
144
142
  {
145
143
  if (cls1 == cls2)
@@ -474,9 +472,6 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
474
472
 
475
473
  void CallData::Execute()
476
474
  {
477
- RG_DEFER_C(prev_call = exec_call) { exec_call = prev_call; };
478
- exec_call = this;
479
-
480
475
  #define PERFORM_CALL(Suffix) \
481
476
  ([&]() { \
482
477
  auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, new_sp, &old_sp) \
@@ -810,8 +805,13 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
810
805
  const TypeInfo *type = proto->ret.type;
811
806
 
812
807
  // Make the call
813
- napi_value ret = CallSwitchStack(&func, (size_t)arguments.len, arguments.data, old_sp, &mem->stack,
814
- [](Napi::Function *func, size_t argc, napi_value *argv) { return (napi_value)func->Call(argv[0], argc - 1, argv + 1); });
808
+ napi_value ret;
809
+ if (async) {
810
+ ret = (napi_value)func.Call(arguments[0], arguments.len - 1, arguments.data + 1);
811
+ } else {
812
+ ret = CallSwitchStack(&func, (size_t)arguments.len, arguments.data, old_sp, &mem->stack,
813
+ [](Napi::Function *func, size_t argc, napi_value *argv) { return (napi_value)func->Call(argv[0], argc - 1, argv + 1); });
814
+ }
815
815
  Napi::Value value(env, ret);
816
816
 
817
817
  if (RG_UNLIKELY(env.IsExceptionPending()))
@@ -990,11 +990,6 @@ void *GetTrampoline(Size idx, const FunctionInfo *proto)
990
990
  return Trampolines[idx][xmm];
991
991
  }
992
992
 
993
- extern "C" void RelayCallback(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
994
- {
995
- exec_call->Relay(idx, own_sp, caller_sp, out_reg);
996
- }
997
-
998
993
  }
999
994
 
1000
995
  #endif
@@ -107,8 +107,6 @@ static void *const Trampolines[][2] = {
107
107
  };
108
108
  RG_STATIC_ASSERT(RG_LEN(Trampolines) == MaxTrampolines * 2);
109
109
 
110
- static RG_THREAD_LOCAL CallData *exec_call;
111
-
112
110
  bool AnalyseFunction(Napi::Env, InstanceData *, FunctionInfo *func)
113
111
  {
114
112
  func->ret.regular = IsRegularSize(func->ret.type->size, 8);
@@ -285,9 +283,6 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
285
283
 
286
284
  void CallData::Execute()
287
285
  {
288
- RG_DEFER_C(prev_call = exec_call) { exec_call = prev_call; };
289
- exec_call = this;
290
-
291
286
  #define PERFORM_CALL(Suffix) \
292
287
  ([&]() { \
293
288
  auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, new_sp, &old_sp) \
@@ -603,8 +598,13 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
603
598
  const TypeInfo *type = proto->ret.type;
604
599
 
605
600
  // Make the call
606
- napi_value ret = CallSwitchStack(&func, (size_t)arguments.len, arguments.data, old_sp, &mem->stack,
607
- [](Napi::Function *func, size_t argc, napi_value *argv) { return (napi_value)func->Call(argv[0], argc - 1, argv + 1); });
601
+ napi_value ret;
602
+ if (async) {
603
+ ret = (napi_value)func.Call(arguments[0], arguments.len - 1, arguments.data + 1);
604
+ } else {
605
+ ret = CallSwitchStack(&func, (size_t)arguments.len, arguments.data, old_sp, &mem->stack,
606
+ [](Napi::Function *func, size_t argc, napi_value *argv) { return (napi_value)func->Call(argv[0], argc - 1, argv + 1); });
607
+ }
608
608
  Napi::Value value(env, ret);
609
609
 
610
610
  if (RG_UNLIKELY(env.IsExceptionPending()))
@@ -764,11 +764,6 @@ void *GetTrampoline(Size idx, const FunctionInfo *proto)
764
764
  return Trampolines[idx][xmm];
765
765
  }
766
766
 
767
- extern "C" void RelayCallback(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
768
- {
769
- exec_call->Relay(idx, own_sp, caller_sp, out_reg);
770
- }
771
-
772
767
  }
773
768
 
774
769
  #endif
@@ -113,8 +113,6 @@ static void *const Trampolines[][2] = {
113
113
  };
114
114
  RG_STATIC_ASSERT(RG_LEN(Trampolines) == MaxTrampolines * 2);
115
115
 
116
- static RG_THREAD_LOCAL CallData *exec_call;
117
-
118
116
  bool AnalyseFunction(Napi::Env env, InstanceData *instance, FunctionInfo *func)
119
117
  {
120
118
  if (!func->lib && func->convention != CallConvention::Cdecl &&
@@ -366,9 +364,6 @@ bool CallData::Prepare(const Napi::CallbackInfo &info)
366
364
 
367
365
  void CallData::Execute()
368
366
  {
369
- RG_DEFER_C(prev_call = exec_call) { exec_call = prev_call; };
370
- exec_call = this;
371
-
372
367
  #define PERFORM_CALL(Suffix) \
373
368
  ([&]() { \
374
369
  auto ret = (func->fast ? ForwardCallR ## Suffix(func->func, new_sp, &old_sp) \
@@ -682,8 +677,13 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
682
677
  const TypeInfo *type = proto->ret.type;
683
678
 
684
679
  // Make the call
685
- napi_value ret = CallSwitchStack(&func, (size_t)arguments.len, arguments.data, old_sp, &mem->stack,
686
- [](Napi::Function *func, size_t argc, napi_value *argv) { return (napi_value)func->Call(argv[0], argc - 1, argv + 1); });
680
+ napi_value ret;
681
+ if (async) {
682
+ ret = (napi_value)func.Call(arguments[0], arguments.len - 1, arguments.data + 1);
683
+ } else {
684
+ ret = CallSwitchStack(&func, (size_t)arguments.len, arguments.data, old_sp, &mem->stack,
685
+ [](Napi::Function *func, size_t argc, napi_value *argv) { return (napi_value)func->Call(argv[0], argc - 1, argv + 1); });
686
+ }
687
687
  Napi::Value value(env, ret);
688
688
 
689
689
  if (RG_UNLIKELY(env.IsExceptionPending()))
@@ -867,11 +867,6 @@ void *GetTrampoline(Size idx, const FunctionInfo *proto)
867
867
  return Trampolines[idx][x87];
868
868
  }
869
869
 
870
- extern "C" void RelayCallback(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
871
- {
872
- exec_call->Relay(idx, own_sp, caller_sp, out_reg);
873
- }
874
-
875
870
  }
876
871
 
877
872
  #endif
@@ -20,9 +20,23 @@
20
20
 
21
21
  namespace RG {
22
22
 
23
- CallData::CallData(Napi::Env env, InstanceData *instance, const FunctionInfo *func, InstanceMemory *mem)
23
+ struct RelayContext {
24
+ CallData *call;
25
+
26
+ Size idx;
27
+ uint8_t *own_sp;
28
+ uint8_t *caller_sp;
29
+ BackRegisters *out_reg;
30
+
31
+ std::mutex mutex;
32
+ std::condition_variable cv;
33
+ bool done = false;
34
+ };
35
+
36
+ CallData::CallData(Napi::Env env, InstanceData *instance,
37
+ const FunctionInfo *func, InstanceMemory *mem, bool async)
24
38
  : env(env), instance(instance), func(func),
25
- mem(mem), old_stack_mem(mem->stack), old_heap_mem(mem->heap)
39
+ mem(mem), old_stack_mem(mem->stack), old_heap_mem(mem->heap), async(async)
26
40
  {
27
41
  mem->generation += !mem->depth;
28
42
  mem->depth++;
@@ -50,6 +64,41 @@ CallData::~CallData()
50
64
  instance = nullptr;
51
65
  }
52
66
 
67
+ void CallData::RelaySafe(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
68
+ {
69
+ if (async) {
70
+ RelayContext ctx;
71
+
72
+ ctx.call = this;
73
+ ctx.idx = idx;
74
+ ctx.own_sp = own_sp;
75
+ ctx.caller_sp = caller_sp;
76
+ ctx.out_reg = out_reg;
77
+
78
+ napi_call_threadsafe_function(instance->broker, &ctx, napi_tsfn_blocking);
79
+
80
+ // Wait until it executes
81
+ std::unique_lock<std::mutex> lock(ctx.mutex);
82
+ while (!ctx.done) {
83
+ ctx.cv.wait(lock);
84
+ }
85
+ } else {
86
+ Relay(idx, own_sp, caller_sp, out_reg);
87
+ }
88
+ }
89
+
90
+ void CallData::RelayAsync(napi_env, napi_value, void *, void *udata)
91
+ {
92
+ RelayContext *ctx = (RelayContext *)udata;
93
+
94
+ ctx->call->Relay(ctx->idx, ctx->own_sp, ctx->caller_sp, ctx->out_reg);
95
+
96
+ // We're done!
97
+ std::lock_guard<std::mutex> lock(ctx->mutex);
98
+ ctx->done = true;
99
+ ctx->cv.notify_one();
100
+ }
101
+
53
102
  bool CallData::PushString(Napi::Value value, int directions, const char **out_str)
54
103
  {
55
104
  if (value.IsString()) {
@@ -42,6 +42,8 @@ class alignas(8) CallData {
42
42
  Span<uint8_t> old_stack_mem;
43
43
  Span<uint8_t> old_heap_mem;
44
44
 
45
+ bool async;
46
+
45
47
  int16_t used_trampolines = 0;
46
48
 
47
49
  LocalArray<OutArgument, MaxOutParameters> out_arguments;
@@ -68,7 +70,8 @@ class alignas(8) CallData {
68
70
  BlockAllocator call_alloc;
69
71
 
70
72
  public:
71
- CallData(Napi::Env env, InstanceData *instance, const FunctionInfo *func, InstanceMemory *mem);
73
+ CallData(Napi::Env env, InstanceData *instance,
74
+ const FunctionInfo *func, InstanceMemory *mem, bool async);
72
75
  ~CallData();
73
76
 
74
77
  #ifdef UNITY_BUILD
@@ -88,6 +91,8 @@ public:
88
91
  #undef INLINE_IF_UNITY
89
92
 
90
93
  void Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg);
94
+ void RelaySafe(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg);
95
+ static void RelayAsync(napi_env, napi_value, void *, void *udata);
91
96
 
92
97
  void DumpForward() const;
93
98
 
@@ -44,6 +44,8 @@ namespace RG {
44
44
  const int TypeInfoMarker = 0xDEADBEEF;
45
45
  const int CastMarker = 0xDEADBEEF;
46
46
 
47
+ static RG_THREAD_LOCAL CallData *exec_call;
48
+
47
49
  static bool ChangeSize(const char *name, Napi::Value value, Size min_size, Size max_size, Size *out_size)
48
50
  {
49
51
  Napi::Env env = value.Env();
@@ -1057,7 +1059,10 @@ static Napi::Value TranslateNormalCall(const Napi::CallbackInfo &info)
1057
1059
  }
1058
1060
 
1059
1061
  InstanceMemory *mem = instance->memories[0];
1060
- CallData call(env, instance, func, mem);
1062
+ CallData call(env, instance, func, mem, false);
1063
+
1064
+ RG_DEFER_C(prev_call = exec_call) { exec_call = prev_call; };
1065
+ exec_call = &call;
1061
1066
 
1062
1067
  if (!RG_UNLIKELY(call.Prepare(info)))
1063
1068
  return env.Null();
@@ -1065,7 +1070,14 @@ static Napi::Value TranslateNormalCall(const Napi::CallbackInfo &info)
1065
1070
  if (instance->debug) {
1066
1071
  call.DumpForward();
1067
1072
  }
1068
- call.Execute();
1073
+
1074
+ // Execute call
1075
+ {
1076
+ RG_DEFER_C(prev_call = exec_call) { exec_call = prev_call; };
1077
+ exec_call = &call;
1078
+
1079
+ call.Execute();
1080
+ }
1069
1081
 
1070
1082
  return call.Complete();
1071
1083
  }
@@ -1124,7 +1136,7 @@ static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
1124
1136
  return env.Null();
1125
1137
 
1126
1138
  InstanceMemory *mem = instance->memories[0];
1127
- CallData call(env, instance, &func, mem);
1139
+ CallData call(env, instance, &func, mem, false);
1128
1140
 
1129
1141
  if (!RG_UNLIKELY(call.Prepare(info)))
1130
1142
  return env.Null();
@@ -1132,7 +1144,14 @@ static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
1132
1144
  if (instance->debug) {
1133
1145
  call.DumpForward();
1134
1146
  }
1135
- call.Execute();
1147
+
1148
+ // Execute call
1149
+ {
1150
+ RG_DEFER_C(prev_call = exec_call) { exec_call = prev_call; };
1151
+ exec_call = &call;
1152
+
1153
+ call.Execute();
1154
+ }
1136
1155
 
1137
1156
  return call.Complete();
1138
1157
  }
@@ -1148,7 +1167,7 @@ public:
1148
1167
  AsyncCall(Napi::Env env, InstanceData *instance, const FunctionInfo *func,
1149
1168
  InstanceMemory *mem, Napi::Function &callback)
1150
1169
  : Napi::AsyncWorker(callback), env(env), func(func->Ref()),
1151
- call(env, instance, func, mem) {}
1170
+ call(env, instance, func, mem, true) {}
1152
1171
  ~AsyncCall() { func->Unref(); }
1153
1172
 
1154
1173
  bool Prepare(const Napi::CallbackInfo &info) {
@@ -1170,6 +1189,9 @@ public:
1170
1189
  void AsyncCall::Execute()
1171
1190
  {
1172
1191
  if (prepared) {
1192
+ RG_DEFER_C(prev_call = exec_call) { exec_call = prev_call; };
1193
+ exec_call = &call;
1194
+
1173
1195
  call.Execute();
1174
1196
  }
1175
1197
  }
@@ -1673,6 +1695,10 @@ InstanceData::~InstanceData()
1673
1695
  for (InstanceMemory *mem: memories) {
1674
1696
  delete mem;
1675
1697
  }
1698
+
1699
+ if (broker) {
1700
+ napi_release_threadsafe_function(broker, napi_tsfn_abort);
1701
+ }
1676
1702
  }
1677
1703
 
1678
1704
  static Napi::Value CastValue(const Napi::CallbackInfo &info)
@@ -1828,6 +1854,30 @@ static Napi::Value DecodeValue(const Napi::CallbackInfo &info)
1828
1854
  return env.Null();
1829
1855
  }
1830
1856
 
1857
+ extern "C" void RelayCallback(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
1858
+ {
1859
+ exec_call->RelaySafe(idx, own_sp, caller_sp, out_reg);
1860
+ }
1861
+
1862
+ static InstanceData *CreateInstance(Napi::Env env)
1863
+ {
1864
+ InstanceData *instance = new InstanceData();
1865
+ RG_DEFER_N(err_guard) { delete instance; };
1866
+
1867
+ Napi::String resource_name = Napi::String::New(env, "Koffi Async Callback Broker");
1868
+
1869
+ if (napi_create_threadsafe_function(env, nullptr, nullptr, resource_name,
1870
+ 0, 1, nullptr, nullptr, nullptr,
1871
+ CallData::RelayAsync, &instance->broker) != napi_ok) {
1872
+ LogError("Failed to create async callback broker");
1873
+ return nullptr;
1874
+ }
1875
+ napi_unref_threadsafe_function(env, instance->broker);
1876
+
1877
+ err_guard.Disable();
1878
+ return instance;
1879
+ }
1880
+
1831
1881
  template <typename Func>
1832
1882
  static void SetExports(Napi::Env env, Func func)
1833
1883
  {
@@ -1906,7 +1956,9 @@ static void InitInternal(v8::Local<v8::Object> target, v8::Local<v8::Value>,
1906
1956
  delete env_napi;
1907
1957
  }, env_napi);
1908
1958
 
1909
- InstanceData *instance = new InstanceData();
1959
+ InstanceData *instance = CreateInstance(env_cxx);
1960
+ RG_CRITICAL(instance, "Failed to initialize Koffi");
1961
+
1910
1962
  env_cxx.SetInstanceData(instance);
1911
1963
 
1912
1964
  instance->debug = GetDebugFlag("DUMP_CALLS");
@@ -1922,7 +1974,9 @@ static Napi::Object InitModule(Napi::Env env, Napi::Object exports)
1922
1974
  {
1923
1975
  using namespace RG;
1924
1976
 
1925
- InstanceData *instance = new InstanceData();
1977
+ InstanceData *instance = CreateInstance(env);
1978
+ RG_CRITICAL(instance, "Failed to initialize Koffi");
1979
+
1926
1980
  env.SetInstanceData(instance);
1927
1981
 
1928
1982
  instance->debug = GetDebugFlag("DUMP_CALLS");
@@ -263,6 +263,8 @@ struct InstanceData {
263
263
  int16_t temp_trampolines = 0;
264
264
  uint32_t registered_trampolines = 0;
265
265
 
266
+ napi_threadsafe_function broker = nullptr;
267
+
266
268
  BlockAllocator str_alloc;
267
269
 
268
270
  Size sync_stack_size = DefaultSyncStackSize;
@@ -18,6 +18,11 @@
18
18
  const util = require('util');
19
19
 
20
20
  let filename = __dirname + '/../build/koffi.node';
21
- module.exports = require(filename);
21
+ let native = require(filename);
22
22
 
23
- module.exports.handle = util.deprecate(module.exports.opaque, 'The koffi.handle() function was deprecated in Koffi 2.1, use koffi.opaque() instead', 'KOFFI001');
23
+ module.exports = {
24
+ ...native,
25
+
26
+ // Deprecated functions
27
+ handle: util.deprecate(native.opaque, 'The koffi.handle() function was deprecated in Koffi 2.1, use koffi.opaque() instead', 'KOFFI001')
28
+ };