koffi 2.15.2 → 2.15.4

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 (45) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/build/koffi/darwin_arm64/koffi.node +0 -0
  3. package/build/koffi/darwin_x64/koffi.node +0 -0
  4. package/build/koffi/freebsd_arm64/koffi.node +0 -0
  5. package/build/koffi/freebsd_ia32/koffi.node +0 -0
  6. package/build/koffi/freebsd_x64/koffi.node +0 -0
  7. package/build/koffi/linux_arm64/koffi.node +0 -0
  8. package/build/koffi/linux_armhf/koffi.node +0 -0
  9. package/build/koffi/linux_ia32/koffi.node +0 -0
  10. package/build/koffi/linux_loong64/koffi.node +0 -0
  11. package/build/koffi/linux_riscv64d/koffi.node +0 -0
  12. package/build/koffi/linux_x64/koffi.node +0 -0
  13. package/build/koffi/musl_arm64/koffi.node +0 -0
  14. package/build/koffi/musl_x64/koffi.node +0 -0
  15. package/build/koffi/openbsd_ia32/koffi.node +0 -0
  16. package/build/koffi/openbsd_x64/koffi.node +0 -0
  17. package/build/koffi/win32_arm64/koffi.node +0 -0
  18. package/build/koffi/win32_ia32/koffi.node +0 -0
  19. package/build/koffi/win32_x64/koffi.node +0 -0
  20. package/index.js +8 -8
  21. package/indirect.js +8 -8
  22. package/package.json +1 -1
  23. package/src/koffi/src/abi_arm32.cc +7 -14
  24. package/src/koffi/src/abi_arm32_asm.S +6 -10
  25. package/src/koffi/src/abi_arm64.cc +11 -17
  26. package/src/koffi/src/abi_arm64_asm.S +4 -7
  27. package/src/koffi/src/abi_arm64_asm.asm +5 -7
  28. package/src/koffi/src/abi_loong64_asm.S +4 -7
  29. package/src/koffi/src/abi_riscv64.cc +7 -14
  30. package/src/koffi/src/abi_riscv64_asm.S +4 -7
  31. package/src/koffi/src/abi_x64_sysv.cc +7 -14
  32. package/src/koffi/src/abi_x64_sysv_asm.S +4 -7
  33. package/src/koffi/src/abi_x64_win.cc +7 -14
  34. package/src/koffi/src/abi_x64_win_asm.S +29 -24
  35. package/src/koffi/src/abi_x64_win_asm.asm +28 -25
  36. package/src/koffi/src/abi_x86.cc +17 -15
  37. package/src/koffi/src/abi_x86_asm.S +11 -17
  38. package/src/koffi/src/abi_x86_asm.asm +6 -14
  39. package/src/koffi/src/call.cc +37 -47
  40. package/src/koffi/src/call.hh +7 -9
  41. package/src/koffi/src/ffi.cc +41 -20
  42. package/src/koffi/src/ffi.hh +1 -1
  43. package/src/koffi/src/util.cc +7 -11
  44. package/src/koffi/src/win32.cc +13 -0
  45. package/src/koffi/src/win32.hh +2 -0
@@ -17,7 +17,7 @@ struct BackRegisters;
17
17
 
18
18
  // I'm not sure why the alignas(8), because alignof(CallData) is 8 without it.
19
19
  // But on Windows i386, without it, the alignment may not be correct (compiler bug?).
20
- class alignas(8) CallData {
20
+ struct alignas(8) CallData {
21
21
  struct OutArgument {
22
22
  enum class Kind {
23
23
  Array,
@@ -66,7 +66,7 @@ class alignas(8) CallData {
66
66
  LocalArray<int16_t, 16> used_trampolines;
67
67
  HeapArray<OutArgument> out_arguments;
68
68
 
69
- BlockAllocator call_alloc;
69
+ BlockAllocator alloc;
70
70
 
71
71
  public:
72
72
  CallData(Napi::Env env, InstanceData *instance, InstanceMemory *mem);
@@ -90,9 +90,8 @@ public:
90
90
 
91
91
  #undef INLINE_IF_UNITY
92
92
 
93
- void Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, bool switch_stack, BackRegisters *out_reg);
94
- void RelaySafe(Size idx, uint8_t *own_sp, uint8_t *caller_sp, bool outside_call, BackRegisters *out_reg);
95
- static void RelayAsync(napi_env, napi_value, void *, void *udata);
93
+ void Relay(Size idx, uint8_t *sp);
94
+ void RelayAsync(Size idx, uint8_t *sp);
96
95
 
97
96
  void DumpForward(const FunctionInfo *func) const;
98
97
 
@@ -112,9 +111,6 @@ public:
112
111
 
113
112
  void *ReserveTrampoline(const FunctionInfo *proto, Napi::Function func);
114
113
 
115
- BlockAllocator *GetAllocator() { return &call_alloc; }
116
-
117
- private:
118
114
  template <typename T>
119
115
  bool AllocStack(Size size, Size align, T **out_ptr);
120
116
  template <typename T = uint8_t>
@@ -169,13 +165,15 @@ inline T *CallData::AllocHeap(Size size, Size align)
169
165
  int flags = 0;
170
166
  #endif
171
167
 
172
- ptr = (uint8_t *)AllocateRaw(&call_alloc, size + align, flags);
168
+ ptr = (uint8_t *)AllocateRaw(&alloc, size + align, flags);
173
169
  ptr = AlignUp(ptr, align);
174
170
 
175
171
  return ptr;
176
172
  }
177
173
  }
178
174
 
175
+ void PerformAsyncRelay(napi_env env, napi_value callback, void *ctx, void *udata);
176
+
179
177
  void *GetTrampoline(int16_t idx, const FunctionInfo *proto);
180
178
 
181
179
  }
@@ -39,6 +39,8 @@ SharedData shared;
39
39
 
40
40
  static thread_local CallData *exec_call;
41
41
 
42
+ extern "C" napi_value SwitchAndRelay(CallData *call, Size idx, uint8_t *sp, uint8_t *saved_sp, Span<uint8_t> *new_stack);
43
+
42
44
  static bool ChangeSize(const char *name, Napi::Value value, Size min_size, Size max_size, Size *out_size)
43
45
  {
44
46
  Napi::Env env = value.Env();
@@ -1690,35 +1692,54 @@ Napi::Value TranslateAsyncCall(const Napi::CallbackInfo &info)
1690
1692
  return TranslateAsyncCall(func, func->native, info);
1691
1693
  }
1692
1694
 
1693
- extern "C" void RelayCallback(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
1695
+ extern "C" void RelayCallback(Size idx, uint8_t *sp)
1694
1696
  {
1695
- if (exec_call) [[likely]] {
1696
- exec_call->RelaySafe(idx, own_sp, caller_sp, false, out_reg);
1697
- } else {
1698
- // This happens if the callback pointer is called from a different thread
1699
- // than the one that runs the FFI call (sync or async).
1697
+ CallData *call = exec_call;
1700
1698
 
1701
- TrampolineInfo *trampoline = &shared.trampolines[idx];
1699
+ // Try the fast path first: we are on the main thread and we are running a native call through Koffi.
1700
+ // It should be easy, but in this case we are running on the custom Koffi stack, which will trip up
1701
+ // Node and V8. So we need to switch back to the normal/main stack.
1702
+ if (call && std::this_thread::get_id() == call->instance->main_thread_id) {
1703
+ SwitchAndRelay(call, idx, sp, call->old_sp, &call->mem->stack);
1704
+ return;
1705
+ }
1702
1706
 
1703
- Napi::Env env = trampoline->func.Env();
1704
- InstanceData *instance = env.GetInstanceData<InstanceData>();
1707
+ // Otherwise, we need to allocate memory to perform the callback.
1708
+ // Since the necessary machinery live in CallData, just use a temporary instance.
1709
+ // In some cases we would reuse the existing call (exec_call may be not null),
1710
+ // but it is rare so let's ignore this for simplicity.
1705
1711
 
1706
- InstanceMemory *mem = AllocateMemory(instance, instance->config.async_stack_size, instance->config.async_heap_size);
1707
- if (!mem) [[unlikely]] {
1708
- ThrowError<Napi::Error>(env, "Too many asynchronous calls are running");
1709
- return;
1710
- }
1712
+ TrampolineInfo *trampoline = &shared.trampolines[idx];
1713
+ Napi::Env env = trampoline->func.Env();
1714
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
1715
+
1716
+ InstanceMemory *mem = AllocateMemory(instance, instance->config.async_stack_size, instance->config.async_heap_size);
1717
+ if (!mem) [[unlikely]] {
1718
+ ThrowError<Napi::Error>(env, "Too many asynchronous calls are running");
1719
+ return;
1720
+ }
1711
1721
 
1712
- // Avoid triggering the "use callback beyond FFI" check
1713
- K_DEFER_C(generation = trampoline->generation) { trampoline->generation = generation; };
1714
- trampoline->generation = -1;
1722
+ // Avoid triggering the "use callback beyond FFI" check
1723
+ K_DEFER_C(generation = trampoline->generation) { trampoline->generation = generation; };
1724
+ trampoline->generation = -1;
1715
1725
 
1716
- // We set dispose_call to true so that the main thread will dispose of CallData itself
1726
+ if (std::this_thread::get_id() == instance->main_thread_id) {
1717
1727
  CallData call(env, instance, mem);
1718
- call.RelaySafe(idx, own_sp, caller_sp, true, out_reg);
1728
+
1729
+ Napi::HandleScope scope(env);
1730
+ call.Relay(idx, sp);
1731
+ } else {
1732
+ CallData call(env, instance, mem);
1733
+ call.RelayAsync(idx, sp);
1719
1734
  }
1720
1735
  }
1721
1736
 
1737
+ extern "C" void RelayDirect(CallData *call, Size idx, uint8_t *sp)
1738
+ {
1739
+ Napi::HandleScope scope(call->env);
1740
+ call->Relay(idx, sp);
1741
+ }
1742
+
1722
1743
  static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info)
1723
1744
  {
1724
1745
  Napi::Env env = info.Env();
@@ -2338,7 +2359,7 @@ bool InitAsyncBroker(Napi::Env env, InstanceData *instance)
2338
2359
  if (napi_create_threadsafe_function(env, nullptr, nullptr,
2339
2360
  Napi::String::New(env, "Koffi Async Callback Broker"),
2340
2361
  0, 1, nullptr, nullptr, nullptr,
2341
- CallData::RelayAsync, &instance->broker) != napi_ok) {
2362
+ PerformAsyncRelay, &instance->broker) != napi_ok) {
2342
2363
  LogError("Failed to create async callback broker");
2343
2364
  return false;
2344
2365
  }
@@ -85,7 +85,7 @@ static const char *const PrimitiveKindNames[] = {
85
85
  struct TypeInfo;
86
86
  struct RecordMember;
87
87
  struct FunctionInfo;
88
- class CallData;
88
+ struct CallData;
89
89
 
90
90
  typedef void DisposeFunc (Napi::Env env, const TypeInfo *type, const void *ptr);
91
91
 
@@ -1683,19 +1683,15 @@ bool Encode(Napi::Env env, uint8_t *origin, Napi::Value value, const TypeInfo *t
1683
1683
  #undef PUSH_INTEGER
1684
1684
 
1685
1685
  // Keep memory around if any was allocated
1686
- {
1687
- BlockAllocator *alloc = call.GetAllocator();
1688
-
1689
- if (alloc->IsUsed()) {
1690
- BlockAllocator *copy = instance->encode_map.FindValue(origin, nullptr);
1686
+ if (call.alloc.IsUsed()) {
1687
+ BlockAllocator *copy = instance->encode_map.FindValue(origin, nullptr);
1691
1688
 
1692
- if (!copy) {
1693
- copy = instance->encode_allocators.AppendDefault();
1694
- instance->encode_map.Set(origin, copy);
1695
- }
1696
-
1697
- std::swap(*alloc, *copy);
1689
+ if (!copy) {
1690
+ copy = instance->encode_allocators.AppendDefault();
1691
+ instance->encode_map.Set(origin, copy);
1698
1692
  }
1693
+
1694
+ std::swap(call.alloc, *copy);
1699
1695
  }
1700
1696
 
1701
1697
  return true;
@@ -180,6 +180,19 @@ int GetDllMachine(const wchar_t *filename)
180
180
  return GetFileMachine(h, true);
181
181
  }
182
182
 
183
+ extern "C" int __cdecl SehHandler(void *ptr, void *, void *ctx, void *)
184
+ {
185
+ EXCEPTION_RECORD *rec = (EXCEPTION_RECORD *)ptr;
186
+
187
+ if (!(rec->ExceptionFlags & (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND))) {
188
+ EXCEPTION_POINTERS ep = { rec, (CONTEXT *)ctx };
189
+ UnhandledExceptionFilter(&ep);
190
+ ExitProcess(rec->ExceptionCode);
191
+ }
192
+
193
+ return ExceptionContinueSearch;
194
+ }
195
+
183
196
  }
184
197
 
185
198
  #endif
@@ -109,4 +109,6 @@ void *LoadWindowsLibrary(Napi::Env env, Span<const char> path); // Returns HANDL
109
109
  int GetSelfMachine();
110
110
  int GetDllMachine(const wchar_t *filename);
111
111
 
112
+ extern "C" int __cdecl SehHandler(void *ptr, void *, void *ctx, void *);
113
+
112
114
  }