koffi 2.2.3-beta.1 → 2.2.3-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/package.json +1 -1
  2. package/src/koffi/build/2.2.3-beta.3/koffi_darwin_arm64.tar.gz +0 -0
  3. package/src/koffi/build/2.2.3-beta.3/koffi_darwin_x64.tar.gz +0 -0
  4. package/src/koffi/build/2.2.3-beta.3/koffi_freebsd_arm64.tar.gz +0 -0
  5. package/src/koffi/build/2.2.3-beta.3/koffi_freebsd_ia32.tar.gz +0 -0
  6. package/src/koffi/build/2.2.3-beta.3/koffi_freebsd_x64.tar.gz +0 -0
  7. package/src/koffi/build/2.2.3-beta.3/koffi_linux_arm32hf.tar.gz +0 -0
  8. package/src/koffi/build/2.2.3-beta.3/koffi_linux_arm64.tar.gz +0 -0
  9. package/src/koffi/build/2.2.3-beta.3/koffi_linux_ia32.tar.gz +0 -0
  10. package/src/koffi/build/2.2.3-beta.3/koffi_linux_riscv64hf64.tar.gz +0 -0
  11. package/src/koffi/build/2.2.3-beta.3/koffi_linux_x64.tar.gz +0 -0
  12. package/src/koffi/build/2.2.3-beta.3/koffi_openbsd_ia32.tar.gz +0 -0
  13. package/src/koffi/build/2.2.3-beta.3/koffi_openbsd_x64.tar.gz +0 -0
  14. package/src/koffi/build/2.2.3-beta.3/koffi_win32_arm64.tar.gz +0 -0
  15. package/src/koffi/build/2.2.3-beta.3/koffi_win32_ia32.tar.gz +0 -0
  16. package/src/koffi/build/2.2.3-beta.3/koffi_win32_x64.tar.gz +0 -0
  17. package/src/koffi/src/abi_x64_win.cc +28 -23
  18. package/src/koffi/src/abi_x86.cc +29 -24
  19. package/src/koffi/src/ffi.cc +86 -36
  20. package/src/koffi/src/ffi.hh +6 -2
  21. package/src/koffi/src/win32.hh +59 -0
  22. package/src/koffi/build/2.2.3-beta.1/koffi_darwin_arm64.tar.gz +0 -0
  23. package/src/koffi/build/2.2.3-beta.1/koffi_darwin_x64.tar.gz +0 -0
  24. package/src/koffi/build/2.2.3-beta.1/koffi_freebsd_arm64.tar.gz +0 -0
  25. package/src/koffi/build/2.2.3-beta.1/koffi_freebsd_ia32.tar.gz +0 -0
  26. package/src/koffi/build/2.2.3-beta.1/koffi_freebsd_x64.tar.gz +0 -0
  27. package/src/koffi/build/2.2.3-beta.1/koffi_linux_arm32hf.tar.gz +0 -0
  28. package/src/koffi/build/2.2.3-beta.1/koffi_linux_arm64.tar.gz +0 -0
  29. package/src/koffi/build/2.2.3-beta.1/koffi_linux_ia32.tar.gz +0 -0
  30. package/src/koffi/build/2.2.3-beta.1/koffi_linux_riscv64hf64.tar.gz +0 -0
  31. package/src/koffi/build/2.2.3-beta.1/koffi_linux_x64.tar.gz +0 -0
  32. package/src/koffi/build/2.2.3-beta.1/koffi_openbsd_ia32.tar.gz +0 -0
  33. package/src/koffi/build/2.2.3-beta.1/koffi_openbsd_x64.tar.gz +0 -0
  34. package/src/koffi/build/2.2.3-beta.1/koffi_win32_arm64.tar.gz +0 -0
  35. package/src/koffi/build/2.2.3-beta.1/koffi_win32_ia32.tar.gz +0 -0
  36. package/src/koffi/build/2.2.3-beta.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.3-beta.1",
3
+ "version": "2.2.3-beta.3",
4
4
  "stable": "2.2.2",
5
5
  "description": "Fast and simple C FFI (foreign function interface) for Node.js",
6
6
  "keywords": [
@@ -17,14 +17,7 @@
17
17
  #include "ffi.hh"
18
18
  #include "call.hh"
19
19
  #include "util.hh"
20
-
21
- #ifndef NOMINMAX
22
- #define NOMINMAX
23
- #endif
24
- #ifndef WIN32_LEAN_AND_MEAN
25
- #define WIN32_LEAN_AND_MEAN
26
- #endif
27
- #include <windows.h>
20
+ #include "win32.hh"
28
21
 
29
22
  #include <napi.h>
30
23
 
@@ -224,15 +217,21 @@ bool CallData::Prepare(const FunctionInfo *func, const Napi::CallbackInfo &info)
224
217
 
225
218
  void CallData::Execute(const FunctionInfo *func)
226
219
  {
227
- NT_TIB *tib = (NT_TIB *)__readgsqword(0x30);
228
-
229
- // Adjust TIB stack limits so SEH works correctly
230
- RG_DEFER_C(base = tib->StackBase, limit = tib->StackLimit) {
231
- tib->StackBase = base;
232
- tib->StackLimit = limit;
220
+ TEB *teb = GetTEB();
221
+
222
+ // Restore previous stack limits at the end
223
+ RG_DEFER_C(base = teb->StackBase,
224
+ limit = teb->StackLimit,
225
+ dealloc = teb->DeallocationStack) {
226
+ teb->StackBase = base;
227
+ teb->StackLimit = limit;
228
+ teb->DeallocationStack = dealloc;
233
229
  };
234
- tib->StackBase = mem->stack0.end();
235
- tib->StackLimit = mem->stack0.ptr;
230
+
231
+ // Adjust stack limits so SEH works correctly
232
+ teb->StackBase = mem->stack0.end();
233
+ teb->StackLimit = mem->stack0.ptr;
234
+ teb->DeallocationStack = mem->stack0.ptr;
236
235
 
237
236
  #define PERFORM_CALL(Suffix) \
238
237
  ([&]() { \
@@ -335,15 +334,21 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, bool async,
335
334
  if (RG_UNLIKELY(env.IsExceptionPending()))
336
335
  return;
337
336
 
338
- NT_TIB *tib = (NT_TIB *)__readgsqword(0x30);
337
+ TEB *teb = GetTEB();
339
338
 
340
- // Restore real thread stack limits
341
- RG_DEFER_C(base = tib->StackBase, limit = tib->StackLimit) {
342
- tib->StackBase = base;
343
- tib->StackLimit = limit;
339
+ // Restore previous stack limits at the end
340
+ RG_DEFER_C(base = teb->StackBase,
341
+ limit = teb->StackLimit,
342
+ dealloc = teb->DeallocationStack) {
343
+ teb->StackBase = base;
344
+ teb->StackLimit = limit;
345
+ teb->DeallocationStack = dealloc;
344
346
  };
345
- tib->StackBase = instance->main_stack_base;
346
- tib->StackLimit = instance->main_stack_limit;
347
+
348
+ // Adjust stack limits so SEH works correctly
349
+ teb->StackBase = instance->main_stack_max;
350
+ teb->StackLimit = instance->main_stack_min;
351
+ teb->DeallocationStack = instance->main_stack_min;
347
352
 
348
353
  const TrampolineInfo &trampoline = shared.trampolines[idx];
349
354
 
@@ -17,15 +17,8 @@
17
17
  #include "ffi.hh"
18
18
  #include "call.hh"
19
19
  #include "util.hh"
20
-
21
20
  #ifdef _WIN32
22
- #ifndef NOMINMAX
23
- #define NOMINMAX
24
- #endif
25
- #ifndef WIN32_LEAN_AND_MEAN
26
- #define WIN32_LEAN_AND_MEAN
27
- #endif
28
- #include <windows.h>
21
+ #include "win32.hh"
29
22
  #endif
30
23
 
31
24
  #include <napi.h>
@@ -308,15 +301,21 @@ bool CallData::Prepare(const FunctionInfo *func, const Napi::CallbackInfo &info)
308
301
  void CallData::Execute(const FunctionInfo *func)
309
302
  {
310
303
  #ifdef _WIN32
311
- NT_TIB *tib = (NT_TIB *)__readfsdword(0x18);
312
-
313
- // Adjust TIB stack limits so SEH works correctly
314
- RG_DEFER_C(base = tib->StackBase, limit = tib->StackLimit) {
315
- tib->StackBase = base;
316
- tib->StackLimit = limit;
304
+ TEB *teb = GetTEB();
305
+
306
+ // Restore previous stack limits at the end
307
+ RG_DEFER_C(base = teb->StackBase,
308
+ limit = teb->StackLimit,
309
+ dealloc = teb->DeallocationStack) {
310
+ teb->StackBase = base;
311
+ teb->StackLimit = limit;
312
+ teb->DeallocationStack = dealloc;
317
313
  };
318
- tib->StackBase = mem->stack0.end();
319
- tib->StackLimit = mem->stack0.ptr;
314
+
315
+ // Adjust stack limits so SEH works correctly
316
+ teb->StackBase = mem->stack0.end();
317
+ teb->StackLimit = mem->stack0.ptr;
318
+ teb->DeallocationStack = mem->stack0.ptr;
320
319
  #endif
321
320
 
322
321
  #define PERFORM_CALL(Suffix) \
@@ -422,15 +421,21 @@ void CallData::Relay(Size idx, uint8_t *, uint8_t *caller_sp, bool async, BackRe
422
421
  return;
423
422
 
424
423
  #ifdef _WIN32
425
- NT_TIB *tib = (NT_TIB *)__readfsdword(0x18);
426
-
427
- // Restore real thread stack limits
428
- RG_DEFER_C(base = tib->StackBase, limit = tib->StackLimit) {
429
- tib->StackBase = base;
430
- tib->StackLimit = limit;
424
+ TEB *teb = GetTEB();
425
+
426
+ // Restore previous stack limits at the end
427
+ RG_DEFER_C(base = teb->StackBase,
428
+ limit = teb->StackLimit,
429
+ dealloc = teb->DeallocationStack) {
430
+ teb->StackBase = base;
431
+ teb->StackLimit = limit;
432
+ teb->DeallocationStack = dealloc;
431
433
  };
432
- tib->StackBase = instance->main_stack_base;
433
- tib->StackLimit = instance->main_stack_limit;
434
+
435
+ // Adjust stack limits so SEH works correctly
436
+ teb->StackBase = instance->main_stack_max;
437
+ teb->StackLimit = instance->main_stack_min;
438
+ teb->DeallocationStack = instance->main_stack_min;
434
439
  #endif
435
440
 
436
441
  const TrampolineInfo &trampoline = shared.trampolines[idx];
@@ -16,6 +16,9 @@
16
16
  #include "call.hh"
17
17
  #include "parser.hh"
18
18
  #include "util.hh"
19
+ #ifdef _WIN32
20
+ #include "win32.hh"
21
+ #endif
19
22
 
20
23
  #ifdef _WIN32
21
24
  #ifndef NOMINMAX
@@ -1014,13 +1017,59 @@ static InstanceMemory *AllocateMemory(InstanceData *instance, Size stack_size, S
1014
1017
  return nullptr;
1015
1018
 
1016
1019
  InstanceMemory *mem = new InstanceMemory();
1020
+ RG_DEFER_N(mem_guard) { delete mem; };
1017
1021
 
1018
- mem->stack.len = stack_size;
1019
1022
  #if defined(_WIN32)
1020
- mem->stack.ptr = (uint8_t *)VirtualAlloc(nullptr, mem->stack.len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
1023
+ {
1024
+ struct FiberContext {
1025
+ InstanceMemory *mem;
1026
+ void *self;
1027
+ bool was_fiber;
1028
+ };
1029
+
1030
+ FiberContext ctx;
1031
+ bool is_fiber = IsThreadAFiber();
1032
+
1033
+ ctx.mem = mem;
1034
+ ctx.self = is_fiber ? GetCurrentFiber() : ConvertThreadToFiber(nullptr);
1035
+ if (!ctx.self) {
1036
+ LogError("Failed to make initial fiber: %1", GetWin32ErrorString());
1037
+ return nullptr;
1038
+ }
1039
+ RG_DEFER {
1040
+ if (!is_fiber) {
1041
+ ConvertFiberToThread();
1042
+ }
1043
+ };
1044
+
1045
+ // Work around issue with CreateFiber() API and stack size
1046
+ // See here: https://github.com/google/marl/issues/12
1047
+ mem->fiber = CreateFiberEx(stack_size - 1, stack_size,
1048
+ FIBER_FLAG_FLOAT_SWITCH, [](void *udata) {
1049
+ FiberContext *ctx = (FiberContext *)udata;
1050
+
1051
+ TEB *teb = GetTEB();
1052
+
1053
+ ctx->mem->stack.ptr = (uint8_t *)teb->DeallocationStack;
1054
+ ctx->mem->stack.len = (uint8_t *)teb->StackBase - ctx->mem->stack.ptr;
1055
+
1056
+ SwitchToFiber(ctx->self);
1057
+ }, &ctx);
1058
+
1059
+ if (!mem->fiber) {
1060
+ LogError("Failed to create Win32 fiber: %1", GetWin32ErrorString());
1061
+ return nullptr;
1062
+ }
1063
+
1064
+ SwitchToFiber(mem->fiber);
1065
+ }
1066
+
1067
+ RG_ASSERT(mem->stack.ptr);
1021
1068
  #elif defined(__APPLE__)
1069
+ mem->stack.len = stack_size;
1022
1070
  mem->stack.ptr = (uint8_t *)mmap(nullptr, mem->stack.len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
1023
1071
  #else
1072
+ mem->stack.len = stack_size;
1024
1073
  mem->stack.ptr = (uint8_t *)mmap(nullptr, mem->stack.len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_STACK, -1, 0);
1025
1074
  #endif
1026
1075
  RG_CRITICAL(mem->stack.ptr, "Failed to allocate %1 of memory", mem->stack.len);
@@ -1051,6 +1100,7 @@ static InstanceMemory *AllocateMemory(InstanceData *instance, Size stack_size, S
1051
1100
  mem->temporary = true;
1052
1101
  }
1053
1102
 
1103
+ mem_guard.Disable();
1054
1104
  return mem;
1055
1105
  }
1056
1106
 
@@ -1691,8 +1741,8 @@ void FunctionInfo::Unref() const
1691
1741
  InstanceMemory::~InstanceMemory()
1692
1742
  {
1693
1743
  #ifdef _WIN32
1694
- if (stack.ptr) {
1695
- VirtualFree(stack.ptr, 0, MEM_RELEASE);
1744
+ if (fiber) {
1745
+ DeleteFiber(fiber);
1696
1746
  }
1697
1747
  if (heap.ptr) {
1698
1748
  VirtualFree(heap.ptr, 0, MEM_RELEASE);
@@ -1707,6 +1757,38 @@ InstanceMemory::~InstanceMemory()
1707
1757
  #endif
1708
1758
  }
1709
1759
 
1760
+ static InstanceData *CreateInstance(Napi::Env env)
1761
+ {
1762
+ InstanceData *instance = new InstanceData();
1763
+ RG_DEFER_N(err_guard) { delete instance; };
1764
+
1765
+ instance->main_thread_id = std::this_thread::get_id();
1766
+
1767
+ if (napi_create_threadsafe_function(env, nullptr, nullptr,
1768
+ Napi::String::New(env, "Koffi Async Callback Broker"),
1769
+ 0, 1, nullptr, nullptr, nullptr,
1770
+ CallData::RelayAsync, &instance->broker) != napi_ok) {
1771
+ LogError("Failed to create async callback broker");
1772
+ return nullptr;
1773
+ }
1774
+ napi_unref_threadsafe_function(env, instance->broker);
1775
+
1776
+ #if defined(_WIN32) && (defined(__x86_64__) || defined(_M_AMD64))
1777
+ void *teb = (void *)__readgsqword(0x30);
1778
+
1779
+ instance->main_stack_max = *(void **)((uint8_t *)teb + 0x08); // StackBase
1780
+ instance->main_stack_min = *(void **)((uint8_t *)teb + 0x1478); // DeallocationStack
1781
+ #elif defined(_WIN32) && (defined(__i386__) || defined(_M_IX86))
1782
+ void *teb = (void *)__readfsdword(0x18);
1783
+
1784
+ instance->main_stack_max = *(void **)((uint8_t *)teb + 0x04); // StackBase
1785
+ instance->main_stack_min = *(void **)((uint8_t *)teb + 0xE0C); // DeallocationStack
1786
+ #endif
1787
+
1788
+ err_guard.Disable();
1789
+ return instance;
1790
+ }
1791
+
1710
1792
  InstanceData::~InstanceData()
1711
1793
  {
1712
1794
  for (InstanceMemory *mem: memories) {
@@ -1916,38 +1998,6 @@ extern "C" void RelayCallback(Size idx, uint8_t *own_sp, uint8_t *caller_sp, Bac
1916
1998
  }
1917
1999
  }
1918
2000
 
1919
- static InstanceData *CreateInstance(Napi::Env env)
1920
- {
1921
- InstanceData *instance = new InstanceData();
1922
- RG_DEFER_N(err_guard) { delete instance; };
1923
-
1924
- instance->main_thread_id = std::this_thread::get_id();
1925
-
1926
- if (napi_create_threadsafe_function(env, nullptr, nullptr,
1927
- Napi::String::New(env, "Koffi Async Callback Broker"),
1928
- 0, 1, nullptr, nullptr, nullptr,
1929
- CallData::RelayAsync, &instance->broker) != napi_ok) {
1930
- LogError("Failed to create async callback broker");
1931
- return nullptr;
1932
- }
1933
- napi_unref_threadsafe_function(env, instance->broker);
1934
-
1935
- #if defined(_WIN32) && (defined(__x86_64__) || defined(_M_AMD64))
1936
- NT_TIB *tib = (NT_TIB *)__readgsqword(0x30);
1937
-
1938
- instance->main_stack_base = tib->StackBase;
1939
- instance->main_stack_limit = tib->StackLimit;
1940
- #elif defined(_WIN32) && (defined(__i386__) || defined(_M_IX86))
1941
- NT_TIB *tib = (NT_TIB *)__readfsdword(0x18);
1942
-
1943
- instance->main_stack_base = tib->StackBase;
1944
- instance->main_stack_limit = tib->StackLimit;
1945
- #endif
1946
-
1947
- err_guard.Disable();
1948
- return instance;
1949
- }
1950
-
1951
2001
  template <typename Func>
1952
2002
  static void SetExports(Napi::Env env, Func func)
1953
2003
  {
@@ -232,6 +232,10 @@ struct InstanceMemory {
232
232
 
233
233
  int16_t depth;
234
234
  bool temporary;
235
+
236
+ #ifdef _WIN32
237
+ void *fiber;
238
+ #endif
235
239
  };
236
240
 
237
241
  struct InstanceData {
@@ -256,8 +260,8 @@ struct InstanceData {
256
260
  napi_threadsafe_function broker = nullptr;
257
261
 
258
262
  #ifdef _WIN32
259
- void *main_stack_base;
260
- void *main_stack_limit;
263
+ void *main_stack_max;
264
+ void *main_stack_min;
261
265
  #endif
262
266
 
263
267
  HashMap<void *, int16_t> trampolines_map;
@@ -0,0 +1,59 @@
1
+ // This program is free software: you can redistribute it and/or modify
2
+ // it under the terms of the GNU Affero General Public License as published by
3
+ // the Free Software Foundation, either version 3 of the License, or
4
+ // (at your option) any later version.
5
+ //
6
+ // This program is distributed in the hope that it will be useful,
7
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
8
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9
+ // GNU Affero General Public License for more details.
10
+ //
11
+ // You should have received a copy of the GNU Affero General Public License
12
+ // along with this program. If not, see https://www.gnu.org/licenses/.
13
+
14
+ #pragma once
15
+
16
+ #include "src/core/libcc/libcc.hh"
17
+
18
+ #include <intrin.h>
19
+
20
+ namespace RG {
21
+
22
+ #if _WIN64
23
+
24
+ struct TEB {
25
+ char _pad1[8];
26
+ void *StackBase;
27
+ void *StackLimit;
28
+ char _pad2[5216];
29
+ void *DeallocationStack;
30
+ };
31
+ RG_STATIC_ASSERT(RG_OFFSET_OF(TEB, DeallocationStack) == 0x1478);
32
+
33
+ #else
34
+
35
+ struct TEB {
36
+ char _pad1[4];
37
+ void *StackBase;
38
+ void *StackLimit;
39
+ char _pad2[3584];
40
+ void *DeallocationStack;
41
+ };
42
+ RG_STATIC_ASSERT(RG_OFFSET_OF(TEB, DeallocationStack) == 0xE0C);
43
+
44
+ #endif
45
+
46
+ static inline TEB *GetTEB()
47
+ {
48
+ #if defined(__aarch64__) || defined(_M_ARM64)
49
+ TEB *teb = (TEB *)__getReg(18);
50
+ #elif defined(__x86_64__) || defined(_M_AMD64)
51
+ TEB *teb = (TEB *)__readgsqword(0x30);
52
+ #else
53
+ TEB *teb = (TEB *)__readfsdword(0x18);
54
+ #endif
55
+
56
+ return teb;
57
+ }
58
+
59
+ }