koffi 1.2.0 → 1.2.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 (49) hide show
  1. package/CMakeLists.txt +1 -1
  2. package/README.md +5 -4
  3. package/benchmark/CMakeLists.txt +1 -1
  4. package/build/qemu/1.2.3/koffi_darwin_arm64.tar.gz +0 -0
  5. package/build/qemu/1.2.3/koffi_darwin_x64.tar.gz +0 -0
  6. package/build/qemu/1.2.3/koffi_freebsd_arm64.tar.gz +0 -0
  7. package/build/qemu/1.2.3/koffi_freebsd_ia32.tar.gz +0 -0
  8. package/build/qemu/1.2.3/koffi_freebsd_x64.tar.gz +0 -0
  9. package/build/qemu/1.2.3/koffi_linux_arm.tar.gz +0 -0
  10. package/build/qemu/1.2.3/koffi_linux_arm64.tar.gz +0 -0
  11. package/build/qemu/1.2.3/koffi_linux_ia32.tar.gz +0 -0
  12. package/build/qemu/1.2.3/koffi_linux_riscv64.tar.gz +0 -0
  13. package/build/qemu/1.2.3/koffi_linux_x64.tar.gz +0 -0
  14. package/build/qemu/1.2.3/koffi_openbsd_ia32.tar.gz +0 -0
  15. package/build/qemu/1.2.3/koffi_openbsd_x64.tar.gz +0 -0
  16. package/build/qemu/1.2.3/koffi_win32_ia32.tar.gz +0 -0
  17. package/build/qemu/1.2.3/koffi_win32_x64.tar.gz +0 -0
  18. package/package.json +1 -1
  19. package/src/abi_arm32.cc +2 -2
  20. package/src/abi_arm32_fwd.S +4 -4
  21. package/src/abi_arm64.cc +2 -2
  22. package/src/abi_arm64_fwd.S +4 -4
  23. package/src/abi_arm64_fwd.asm +5 -5
  24. package/src/abi_riscv64.cc +2 -2
  25. package/src/abi_riscv64_fwd.S +4 -4
  26. package/src/abi_x64_sysv.cc +2 -2
  27. package/src/abi_x64_sysv_fwd.S +4 -4
  28. package/src/abi_x64_win.cc +2 -2
  29. package/src/abi_x64_win_fwd.asm +4 -4
  30. package/src/abi_x86.cc +26 -14
  31. package/src/abi_x86_fwd.S +15 -16
  32. package/src/abi_x86_fwd.asm +15 -9
  33. package/src/call.hh +1 -1
  34. package/src/ffi.cc +3 -8
  35. package/test/callbacks.js +8 -0
  36. package/test/misc.c +8 -0
  37. package/build/qemu/1.2.0/koffi_darwin_x64.tar.gz +0 -0
  38. package/build/qemu/1.2.0/koffi_freebsd_arm64.tar.gz +0 -0
  39. package/build/qemu/1.2.0/koffi_freebsd_ia32.tar.gz +0 -0
  40. package/build/qemu/1.2.0/koffi_freebsd_x64.tar.gz +0 -0
  41. package/build/qemu/1.2.0/koffi_linux_arm.tar.gz +0 -0
  42. package/build/qemu/1.2.0/koffi_linux_arm64.tar.gz +0 -0
  43. package/build/qemu/1.2.0/koffi_linux_ia32.tar.gz +0 -0
  44. package/build/qemu/1.2.0/koffi_linux_riscv64.tar.gz +0 -0
  45. package/build/qemu/1.2.0/koffi_linux_x64.tar.gz +0 -0
  46. package/build/qemu/1.2.0/koffi_openbsd_ia32.tar.gz +0 -0
  47. package/build/qemu/1.2.0/koffi_openbsd_x64.tar.gz +0 -0
  48. package/build/qemu/1.2.0/koffi_win32_ia32.tar.gz +0 -0
  49. package/build/qemu/1.2.0/koffi_win32_x64.tar.gz +0 -0
package/CMakeLists.txt CHANGED
@@ -18,7 +18,7 @@ find_package(CNoke)
18
18
 
19
19
  set(CMAKE_CXX_STANDARD 17)
20
20
  if(MSVC)
21
- add_compile_options(/W4 /wd4200 /wd4458 /wd4706 /wd4100 /wd4127 /wd4702 /wd4201)
21
+ add_compile_options(/W4 /wd4200 /wd4458 /wd4706 /wd4100 /wd4127 /wd4702 /wd4201 /wd4324)
22
22
  enable_language(ASM_MASM)
23
23
  else()
24
24
  add_compile_options(-Wall -Wextra -Wno-missing-field-initializers -Wno-unused-parameter)
package/README.md CHANGED
@@ -33,13 +33,12 @@ ISA / OS | Windows | Linux | macOS | FreeBSD | OpenBS
33
33
  x86 (IA32) [^1] | 🟩 Yes | 🟩 Yes | ⬜️ *N/A* | 🟩 Yes | 🟩 Yes
34
34
  x86_64 (AMD64) | 🟩 Yes | 🟩 Yes | 🟩 Yes | 🟩 Yes | 🟩 Yes
35
35
  ARM32 LE [^2] | ⬜️ *N/A* | 🟩 Yes | ⬜️ *N/A* | 🟨 Probably | 🟨 Probably
36
- ARM64 (AArch64) LE | 🟧 Maybe | 🟩 Yes | 🟩 Yes [^3] | 🟩 Yes | 🟨 Probably
37
- RISC-V 64 [^4] | ⬜️ *N/A* | 🟩 Yes | ⬜️ *N/A* | 🟨 Probably | 🟨 Probably
36
+ ARM64 (AArch64) LE | 🟧 Maybe | 🟩 Yes | 🟩 Yes | 🟩 Yes | 🟨 Probably
37
+ RISC-V 64 [^3] | ⬜️ *N/A* | 🟩 Yes | ⬜️ *N/A* | 🟨 Probably | 🟨 Probably
38
38
 
39
39
  [^1]: The following call conventions are supported: cdecl, stdcall, MS fastcall, thiscall.
40
40
  [^2]: The prebuilt binary uses the hard float ABI and expects a VFP coprocessor. Build from source to use Koffi with a different ABI (softfp, soft).
41
- [^3]: However, we don't provide prebuilt binaries for macOS on Apple M1.
42
- [^4]: Only the LP64D (double-precision float) ABI gets tested. The LP64 ABI is supported in theory (untested), the LP64F ABI is not supported.
41
+ [^3]: Only the LP64D (double-precision float) ABI gets tested. The LP64 ABI is supported in theory (untested), the LP64F ABI is not supported.
43
42
 
44
43
  The following features are planned in the near future:
45
44
 
@@ -341,6 +340,8 @@ console.log(ret);
341
340
  // This example prints "Hello Niels!" first, and then prints 42
342
341
  ```
343
342
 
343
+ On x86 platforms, only Cdecl and Stdcall callbacks are supported.
344
+
344
345
  ## Memory settings
345
346
 
346
347
  For synchronous/normal calls, Koffi uses two preallocated memory blocks, one to construct the C stack and the other to allocate strings and big objects/structs. Unless very big strings or objects (at least more than one page of memory) are used, no extra allocation is needed during calls or callbacks.
@@ -26,7 +26,7 @@ add_subdirectory(../test test)
26
26
 
27
27
  set(CMAKE_CXX_STANDARD 17)
28
28
  if(MSVC)
29
- add_compile_options(/W4 /wd4200 /wd4458 /wd4706 /wd4100 /wd4127 /wd4702 /wd4201)
29
+ add_compile_options(/W4 /wd4200 /wd4458 /wd4706 /wd4100 /wd4127 /wd4702 /wd4201 /wd4324)
30
30
  else()
31
31
  add_compile_options(-Wall -Wextra -Wno-missing-field-initializers -Wno-unused-parameter)
32
32
  if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "koffi",
3
- "version": "1.2.0",
3
+ "version": "1.2.3",
4
4
  "description": "Fast and simple C FFI (foreign function interface) for Node.js",
5
5
  "keywords": [
6
6
  "foreign",
package/src/abi_arm32.cc CHANGED
@@ -100,7 +100,7 @@ static inline int IsHFA(const TypeInfo *type)
100
100
  #endif
101
101
  }
102
102
 
103
- bool AnalyseFunction(InstanceData *, FunctionInfo *func)
103
+ bool AnalyseFunction(Napi::Env, InstanceData *, FunctionInfo *func)
104
104
  {
105
105
  if (int hfa = IsHFA(func->ret.type); hfa) {
106
106
  func->ret.vec_count = hfa;
@@ -931,7 +931,7 @@ void *GetTrampoline(Size idx, const FunctionInfo *proto)
931
931
  return Trampolines[idx][vec];
932
932
  }
933
933
 
934
- extern "C" void RelayCallBack(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
934
+ extern "C" void RelayCallback(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
935
935
  {
936
936
  exec_call->Relay(idx, own_sp, caller_sp, out_reg);
937
937
  }
@@ -144,11 +144,11 @@ ForwardCallXDDDD:
144
144
  .global TrampolineX13
145
145
  .global TrampolineX14
146
146
  .global TrampolineX15
147
- .global RelayCallBack
147
+ .global RelayCallback
148
148
  .global CallSwitchStack
149
149
 
150
150
  # First, make a copy of the GPR argument registers (r0 to r7).
151
- # Then call the C function RelayCallBack with the following arguments:
151
+ # Then call the C function RelayCallback with the following arguments:
152
152
  # static trampoline ID, a pointer to the saved GPR array, a pointer to the stack
153
153
  # arguments of this call, and a pointer to a struct that will contain the result registers.
154
154
  # After the call, simply load these registers from the output struct.
@@ -168,7 +168,7 @@ ForwardCallXDDDD:
168
168
  mov r1, sp
169
169
  add r2, sp, #128
170
170
  add r3, sp, #80
171
- bl RelayCallBack
171
+ bl RelayCallback
172
172
  ldr r0, [sp, 80]
173
173
  ldr r1, [sp, 84]
174
174
  add sp, sp, #120
@@ -206,7 +206,7 @@ ForwardCallXDDDD:
206
206
  mov r1, sp
207
207
  add r2, sp, #128
208
208
  add r3, sp, #80
209
- bl RelayCallBack
209
+ bl RelayCallback
210
210
  ldr r0, [sp, 80]
211
211
  ldr r1, [sp, 84]
212
212
  vldr d0, [sp, 88]
package/src/abi_arm64.cc CHANGED
@@ -98,7 +98,7 @@ static inline int IsHFA(const TypeInfo *type)
98
98
  return IsHFA(type, 1, 4);
99
99
  }
100
100
 
101
- bool AnalyseFunction(InstanceData *, FunctionInfo *func)
101
+ bool AnalyseFunction(Napi::Env, InstanceData *, FunctionInfo *func)
102
102
  {
103
103
  if (int hfa = IsHFA(func->ret.type); hfa) {
104
104
  func->ret.vec_count = hfa;
@@ -999,7 +999,7 @@ void *GetTrampoline(Size idx, const FunctionInfo *proto)
999
999
  return Trampolines[idx][vec];
1000
1000
  }
1001
1001
 
1002
- extern "C" void RelayCallBack(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
1002
+ extern "C" void RelayCallback(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
1003
1003
  {
1004
1004
  exec_call->Relay(idx, own_sp, caller_sp, out_reg);
1005
1005
  }
@@ -147,11 +147,11 @@ SYMBOL(ForwardCallXDDDD):
147
147
  .global SYMBOL(TrampolineX13)
148
148
  .global SYMBOL(TrampolineX14)
149
149
  .global SYMBOL(TrampolineX15)
150
- .global SYMBOL(RelayCallBack)
150
+ .global SYMBOL(RelayCallback)
151
151
  .global SYMBOL(CallSwitchStack)
152
152
 
153
153
  # First, make a copy of the GPR argument registers (x0 to x7).
154
- # Then call the C function RelayCallBack with the following arguments:
154
+ # Then call the C function RelayCallback with the following arguments:
155
155
  # static trampoline ID, a pointer to the saved GPR array, a pointer to the stack
156
156
  # arguments of this call, and a pointer to a struct that will contain the result registers.
157
157
  # After the call, simply load these registers from the output struct.
@@ -172,7 +172,7 @@ SYMBOL(ForwardCallXDDDD):
172
172
  mov x1, sp
173
173
  add x2, sp, #208
174
174
  add x3, sp, #136
175
- bl SYMBOL(RelayCallBack)
175
+ bl SYMBOL(RelayCallback)
176
176
  ldp x0, x1, [sp, 136]
177
177
  add sp, sp, #192
178
178
  .cfi_def_cfa sp, 16
@@ -206,7 +206,7 @@ SYMBOL(ForwardCallXDDDD):
206
206
  mov x1, sp
207
207
  add x2, sp, #208
208
208
  add x3, sp, #136
209
- bl SYMBOL(RelayCallBack)
209
+ bl SYMBOL(RelayCallback)
210
210
  ldp x0, x1, [sp, 136]
211
211
  ldp d0, d1, [sp, 152]
212
212
  ldp d2, d3, [sp, 168]
@@ -145,12 +145,12 @@ ForwardCallXDDDD PROC
145
145
  EXPORT TrampolineX13
146
146
  EXPORT TrampolineX14
147
147
  EXPORT TrampolineX15
148
- EXPORT RelayCallBack
149
- EXTERN RelayCallBack
148
+ EXPORT RelayCallback
149
+ EXTERN RelayCallback
150
150
  EXPORT CallSwitchStack
151
151
 
152
152
  ; First, make a copy of the GPR argument registers (x0 to x7).
153
- ; Then call the C function RelayCallBack with the following arguments:
153
+ ; Then call the C function RelayCallback with the following arguments:
154
154
  ; static trampoline ID, a pointer to the saved GPR array, a pointer to the stack
155
155
  ; arguments of this call, and a pointer to a struct that will contain the result registers.
156
156
  ; After the call, simply load these registers from the output struct.
@@ -168,7 +168,7 @@ ForwardCallXDDDD PROC
168
168
  mov x1, sp
169
169
  add x2, sp, #208
170
170
  add x3, sp, #136
171
- bl RelayCallBack
171
+ bl RelayCallback
172
172
  ldp x0, x1, [sp, 136]
173
173
  add sp, sp, #192
174
174
  ldp x29, x30, [sp], 16
@@ -194,7 +194,7 @@ ForwardCallXDDDD PROC
194
194
  mov x1, sp
195
195
  add x2, sp, #208
196
196
  add x3, sp, #136
197
- bl RelayCallBack
197
+ bl RelayCallback
198
198
  ldp x0, x1, [sp, 136]
199
199
  ldp d0, d1, [sp, 152]
200
200
  ldp d2, d3, [sp, 168]
@@ -146,7 +146,7 @@ static void AnalyseParameter(ParameterInfo *param, int gpr_avail, int vec_avail)
146
146
  }
147
147
  }
148
148
 
149
- bool AnalyseFunction(InstanceData *, FunctionInfo *func)
149
+ bool AnalyseFunction(Napi::Env, InstanceData *, FunctionInfo *func)
150
150
  {
151
151
  AnalyseParameter(&func->ret, 2, 2);
152
152
 
@@ -817,7 +817,7 @@ void *GetTrampoline(Size idx, const FunctionInfo *proto)
817
817
  return Trampolines[idx][fp];
818
818
  }
819
819
 
820
- extern "C" void RelayCallBack(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
820
+ extern "C" void RelayCallback(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
821
821
  {
822
822
  exec_call->Relay(idx, own_sp, caller_sp, out_reg);
823
823
  }
@@ -168,11 +168,11 @@ ForwardCallXDD:
168
168
  .global TrampolineX13
169
169
  .global TrampolineX14
170
170
  .global TrampolineX15
171
- .global RelayCallBack
171
+ .global RelayCallback
172
172
  .global CallSwitchStack
173
173
 
174
174
  # First, make a copy of the GPR argument registers (a0 to a7).
175
- # Then call the C function RelayCallBack with the following arguments:
175
+ # Then call the C function RelayCallback with the following arguments:
176
176
  # static trampoline ID, a pointer to the saved GPR array, a pointer to the stack
177
177
  # arguments of this call, and a pointer to a struct that will contain the result registers.
178
178
  # After the call, simply load these registers from the output struct.
@@ -191,7 +191,7 @@ ForwardCallXDD:
191
191
  addi a1, sp, 8
192
192
  addi a2, sp, 176
193
193
  addi a3, sp, 136
194
- jal RelayCallBack
194
+ jal RelayCallback
195
195
  ld ra, 0(sp)
196
196
  ld a0, 136(sp)
197
197
  ld a1, 144(sp)
@@ -223,7 +223,7 @@ ForwardCallXDD:
223
223
  addi a1, sp, 8
224
224
  addi a2, sp, 176
225
225
  addi a3, sp, 136
226
- jal RelayCallBack
226
+ jal RelayCallback
227
227
  ld ra, 0(sp)
228
228
  ld a0, 136(sp)
229
229
  ld a1, 144(sp)
@@ -225,7 +225,7 @@ static void AnalyseParameter(ParameterInfo *param, int gpr_avail, int xmm_avail)
225
225
  }
226
226
  }
227
227
 
228
- bool AnalyseFunction(InstanceData *, FunctionInfo *func)
228
+ bool AnalyseFunction(Napi::Env, InstanceData *, FunctionInfo *func)
229
229
  {
230
230
  AnalyseParameter(&func->ret, 2, 2);
231
231
 
@@ -874,7 +874,7 @@ void *GetTrampoline(Size idx, const FunctionInfo *proto)
874
874
  return Trampolines[idx][xmm];
875
875
  }
876
876
 
877
- extern "C" void RelayCallBack(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
877
+ extern "C" void RelayCallback(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
878
878
  {
879
879
  exec_call->Relay(idx, own_sp, caller_sp, out_reg);
880
880
  }
@@ -185,11 +185,11 @@ SYMBOL(ForwardCallXDD):
185
185
  .global SYMBOL(TrampolineX13)
186
186
  .global SYMBOL(TrampolineX14)
187
187
  .global SYMBOL(TrampolineX15)
188
- .global SYMBOL(RelayCallBack)
188
+ .global SYMBOL(RelayCallback)
189
189
  .global SYMBOL(CallSwitchStack)
190
190
 
191
191
  # First, make a copy of the GPR argument registers (rdi, rsi, rdx, rcx, r8, r9).
192
- # Then call the C function RelayCallBack with the following arguments:
192
+ # Then call the C function RelayCallback with the following arguments:
193
193
  # static trampoline ID, a pointer to the saved GPR array, a pointer to the stack
194
194
  # arguments of this call, and a pointer to a struct that will contain the result registers.
195
195
  # After the call, simply load these registers from the output struct.
@@ -209,7 +209,7 @@ SYMBOL(ForwardCallXDD):
209
209
  movq %rsp, %rsi
210
210
  leaq 160(%rsp), %rdx
211
211
  leaq 112(%rsp), %rcx
212
- call SYMBOL(RelayCallBack)
212
+ call SYMBOL(RelayCallback)
213
213
  movq 112(%rsp), %rax
214
214
  movq 120(%rsp), %rdx
215
215
  addq $152, %rsp
@@ -243,7 +243,7 @@ SYMBOL(ForwardCallXDD):
243
243
  movq %rsp, %rsi
244
244
  leaq 160(%rsp), %rdx
245
245
  leaq 112(%rsp), %rcx
246
- call SYMBOL(RelayCallBack)
246
+ call SYMBOL(RelayCallback)
247
247
  movq 112(%rsp), %rax
248
248
  movq 120(%rsp), %rdx
249
249
  movsd 128(%rsp), %xmm0
@@ -83,7 +83,7 @@ static inline bool IsRegular(Size size)
83
83
  return regular;
84
84
  }
85
85
 
86
- bool AnalyseFunction(InstanceData *, FunctionInfo *func)
86
+ bool AnalyseFunction(Napi::Env, InstanceData *, FunctionInfo *func)
87
87
  {
88
88
  func->ret.regular = IsRegular(func->ret.type->size);
89
89
 
@@ -656,7 +656,7 @@ void *GetTrampoline(Size idx, const FunctionInfo *proto)
656
656
  return Trampolines[idx][xmm];
657
657
  }
658
658
 
659
- extern "C" void RelayCallBack(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
659
+ extern "C" void RelayCallback(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
660
660
  {
661
661
  exec_call->Relay(idx, own_sp, caller_sp, out_reg);
662
662
  }
@@ -142,11 +142,11 @@ public TrampolineX12
142
142
  public TrampolineX13
143
143
  public TrampolineX14
144
144
  public TrampolineX15
145
- extern RelayCallBack : PROC
145
+ extern RelayCallback : PROC
146
146
  public CallSwitchStack
147
147
 
148
148
  ; First, make a copy of the GPR argument registers (rcx, rdx, r8, r9).
149
- ; Then call the C function RelayCallBack with the following arguments:
149
+ ; Then call the C function RelayCallback with the following arguments:
150
150
  ; static trampoline ID, a pointer to the saved GPR array, a pointer to the stack
151
151
  ; arguments of this call, and a pointer to a struct that will contain the result registers.
152
152
  ; After the call, simply load these registers from the output struct.
@@ -163,7 +163,7 @@ trampoline macro ID
163
163
  lea rdx, qword ptr [rsp+32]
164
164
  lea r8, qword ptr [rsp+128]
165
165
  lea r9, qword ptr [rsp+96]
166
- call RelayCallBack
166
+ call RelayCallback
167
167
  mov rax, qword ptr [rsp+96]
168
168
  add rsp, 120
169
169
  ret
@@ -187,7 +187,7 @@ trampoline_xmm macro ID
187
187
  lea rdx, qword ptr [rsp+32]
188
188
  lea r8, qword ptr [rsp+128]
189
189
  lea r9, qword ptr [rsp+96]
190
- call RelayCallBack
190
+ call RelayCallback
191
191
  mov rax, qword ptr [rsp+96]
192
192
  movsd xmm0, qword ptr [rsp+104]
193
193
  add rsp, 120
package/src/abi_x86.cc CHANGED
@@ -25,12 +25,12 @@ namespace RG {
25
25
  struct BackRegisters {
26
26
  uint32_t eax;
27
27
  uint32_t edx;
28
- double d;
29
- float f;
30
- bool is_double;
31
- #ifndef _WIN32
32
- bool ret4;
33
- #endif
28
+ union {
29
+ double d;
30
+ float f;
31
+ } x87;
32
+ bool x87_double;
33
+ int ret_pop;
34
34
  };
35
35
 
36
36
  extern "C" uint64_t ForwardCallG(const void *func, uint8_t *sp, uint8_t **out_old_sp);
@@ -89,8 +89,14 @@ static inline bool IsRegular(Size size)
89
89
  return regular;
90
90
  }
91
91
 
92
- bool AnalyseFunction(InstanceData *instance, FunctionInfo *func)
92
+ bool AnalyseFunction(Napi::Env env, InstanceData *instance, FunctionInfo *func)
93
93
  {
94
+ if (!func->lib && func->convention != CallConvention::Cdecl &&
95
+ func->convention != CallConvention::Stdcall) {
96
+ ThrowError<Napi::Error>(env, "Only Cdecl and Stdcall callbacks are supported");
97
+ return false;
98
+ }
99
+
94
100
  int fast = (func->convention == CallConvention::Fastcall) ? 2 :
95
101
  (func->convention == CallConvention::Thiscall) ? 1 : 0;
96
102
  func->fast = fast;
@@ -116,7 +122,7 @@ bool AnalyseFunction(InstanceData *instance, FunctionInfo *func)
116
122
  fast--;
117
123
  }
118
124
 
119
- params_size += std::max((int16_t)4, param.type->size);
125
+ params_size += std::max(4, AlignLen(param.type->size, 4));
120
126
  }
121
127
  func->args_size = params_size + 4 * !func->ret.trivial;
122
128
 
@@ -441,9 +447,15 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
441
447
  uint8_t *return_ptr = !proto->ret.trivial ? (uint8_t *)args_ptr[0] : nullptr;
442
448
  args_ptr += !proto->ret.trivial;
443
449
 
450
+ if (proto->convention == CallConvention::Stdcall) {
451
+ out_reg->ret_pop = (int)proto->args_size;
444
452
  #ifndef _WIN32
445
- out_reg->ret4 = !!return_ptr;
453
+ } else if (return_ptr) {
454
+ out_reg->ret_pop = 4;
446
455
  #endif
456
+ } else {
457
+ out_reg->ret_pop = 0;
458
+ }
447
459
 
448
460
  LocalArray<napi_value, MaxParameters> arguments;
449
461
 
@@ -680,8 +692,8 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
680
692
  return;
681
693
  }
682
694
 
683
- out_reg->f = CopyNumber<float>(value);
684
- out_reg->is_double = false;
695
+ out_reg->x87.f = CopyNumber<float>(value);
696
+ out_reg->x87_double = false;
685
697
  } break;
686
698
  case PrimitiveKind::Float64: {
687
699
  if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
@@ -689,8 +701,8 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegister
689
701
  return;
690
702
  }
691
703
 
692
- out_reg->d = CopyNumber<double>(value);
693
- out_reg->is_double = true;
704
+ out_reg->x87.d = CopyNumber<double>(value);
705
+ out_reg->x87_double = true;
694
706
  } break;
695
707
  case PrimitiveKind::Callback: {
696
708
  void *ptr;
@@ -721,7 +733,7 @@ void *GetTrampoline(Size idx, const FunctionInfo *proto)
721
733
  return Trampolines[idx][x87];
722
734
  }
723
735
 
724
- extern "C" void RelayCallBack(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
736
+ extern "C" void RelayCallback(Size idx, uint8_t *own_sp, uint8_t *caller_sp, BackRegisters *out_reg)
725
737
  {
726
738
  exec_call->Relay(idx, own_sp, caller_sp, out_reg);
727
739
  }
package/src/abi_x86_fwd.S CHANGED
@@ -115,10 +115,10 @@ ForwardCallRD:
115
115
  .global TrampolineX13
116
116
  .global TrampolineX14
117
117
  .global TrampolineX15
118
- .global RelayCallBack
118
+ .global RelayCallback
119
119
  .global CallSwitchStack
120
120
 
121
- # Call the C function RelayCallBack with the following arguments:
121
+ # Call the C function RelayCallback with the following arguments:
122
122
  # static trampoline ID, the current stack pointer, a pointer to the stack arguments of this call,
123
123
  # and a pointer to a struct that will contain the result registers.
124
124
  # After the call, simply load these registers from the output struct.
@@ -136,19 +136,15 @@ ForwardCallRD:
136
136
  movl %eax, 12(%esp)
137
137
  call GetEIP
138
138
  addl $_GLOBAL_OFFSET_TABLE_, %ecx
139
- call *RelayCallBack@GOT(%ecx)
139
+ call *RelayCallback@GOT(%ecx)
140
+ movl 44(%esp), %edx
141
+ movl 36(%esp), %ecx
142
+ movl %edx, 44(%esp, %ecx)
140
143
  movl 16(%esp), %eax
141
144
  movl 20(%esp), %edx
142
- cmpb $0, 37(%esp)
143
- jne 2f
144
- 1:
145
- addl $44, %esp
145
+ leal 44(%esp, %ecx), %esp
146
146
  .cfi_def_cfa esp, 4
147
147
  ret
148
- 2:
149
- addl $44, %esp
150
- .cfi_def_cfa esp, 4
151
- ret $4
152
148
  .cfi_endproc
153
149
  .endm
154
150
 
@@ -168,17 +164,20 @@ ForwardCallRD:
168
164
  movl %eax, 12(%esp)
169
165
  call GetEIP
170
166
  addl $_GLOBAL_OFFSET_TABLE_, %ecx
171
- call *RelayCallBack@GOT(%ecx)
172
- cmpb $0, 36(%esp)
167
+ call *RelayCallback@GOT(%ecx)
168
+ movl 44(%esp), %edx
169
+ movl 36(%esp), %ecx
170
+ movl %edx, 44(%esp, %ecx, 4)
171
+ cmpb $0, 32(%esp)
173
172
  jne 2f
174
173
  1:
175
- flds 32(%esp)
176
- addl $44, %esp
174
+ flds 24(%esp)
175
+ leal 44(%esp, %ecx), %esp
177
176
  .cfi_def_cfa esp, 4
178
177
  ret
179
178
  2:
180
179
  fldl 24(%esp)
181
- addl $44, %esp
180
+ leal 44(%esp, %ecx), %esp
182
181
  .cfi_def_cfa esp, 4
183
182
  ret
184
183
  .cfi_endproc
@@ -121,10 +121,10 @@ public TrampolineX12
121
121
  public TrampolineX13
122
122
  public TrampolineX14
123
123
  public TrampolineX15
124
- extern RelayCallBack : PROC
124
+ extern RelayCallback : PROC
125
125
  public CallSwitchStack
126
126
 
127
- ; Call the C function RelayCallBack with the following arguments:
127
+ ; Call the C function RelayCallback with the following arguments:
128
128
  ; static trampoline ID, the current stack pointer, a pointer to the stack arguments of this call,
129
129
  ; and a pointer to a struct that will contain the result registers.
130
130
  ; After the call, simply load these registers from the output struct.
@@ -137,10 +137,13 @@ trampoline macro ID
137
137
  mov dword ptr [esp+8], eax
138
138
  lea eax, dword ptr [esp+16]
139
139
  mov dword ptr [esp+12], eax
140
- call RelayCallBack
140
+ call RelayCallback
141
+ mov edx, dword ptr [esp+44]
142
+ mov ecx, dword ptr [esp+36]
143
+ mov dword ptr [esp+ecx+44], edx
141
144
  mov eax, dword ptr [esp+16]
142
145
  mov edx, dword ptr [esp+20]
143
- add esp, 44
146
+ lea esp, [esp+ecx+44]
144
147
  ret
145
148
  endm
146
149
 
@@ -157,16 +160,19 @@ trampoline_x87 macro ID
157
160
  mov dword ptr [esp+8], eax
158
161
  lea eax, dword ptr [esp+16]
159
162
  mov dword ptr [esp+12], eax
160
- call RelayCallBack
161
- cmp byte ptr [esp+36], 0
163
+ call RelayCallback
164
+ mov edx, dword ptr [esp+44]
165
+ mov ecx, dword ptr [esp+36]
166
+ mov dword ptr [esp+ecx+44], edx
167
+ cmp byte ptr [esp+32], 0
162
168
  jne l2
163
169
  l1:
164
- fld dword ptr [esp+32]
165
- add esp, 44
170
+ fld dword ptr [esp+24]
171
+ lea esp, dword ptr [esp+ecx+44]
166
172
  ret
167
173
  l2:
168
174
  fld qword ptr [esp+24]
169
- add esp, 44
175
+ lea esp, dword ptr [esp+ecx+44]
170
176
  ret
171
177
  endm
172
178
 
package/src/call.hh CHANGED
@@ -21,7 +21,7 @@
21
21
 
22
22
  namespace RG {
23
23
 
24
- bool AnalyseFunction(InstanceData *instance, FunctionInfo *func);
24
+ bool AnalyseFunction(Napi::Env env, InstanceData *instance, FunctionInfo *func);
25
25
 
26
26
  struct BackRegisters;
27
27
 
package/src/ffi.cc CHANGED
@@ -511,13 +511,8 @@ static Napi::Value CreateCallbackType(const Napi::CallbackInfo &info)
511
511
  LogError("Variadic callbacks are not supported");
512
512
  return env.Null();
513
513
  }
514
- if (func->convention != CallConvention::Cdecl &&
515
- func->convention != CallConvention::Stdcall) {
516
- ThrowError<Napi::Error>(env, "Only Cdecl and Stdcall callbacks are supported");
517
- return env.Null();
518
- }
519
514
 
520
- if (!AnalyseFunction(instance, func))
515
+ if (!AnalyseFunction(env, instance, func))
521
516
  return env.Null();
522
517
 
523
518
  // We cannot fail after this check
@@ -713,7 +708,7 @@ static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
713
708
  func.parameters.Append(param);
714
709
  }
715
710
 
716
- if (RG_UNLIKELY(!AnalyseFunction(instance, &func)))
711
+ if (RG_UNLIKELY(!AnalyseFunction(env, instance, &func)))
717
712
  return env.Null();
718
713
 
719
714
  InstanceMemory *mem = instance->memories[0];
@@ -846,7 +841,7 @@ static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info, CallConve
846
841
  func->convention = CallConvention::Cdecl;
847
842
  }
848
843
 
849
- if (!AnalyseFunction(instance, func))
844
+ if (!AnalyseFunction(env, instance, func))
850
845
  return env.Null();
851
846
  if (func->variadic) {
852
847
  // Minimize reallocations
package/test/callbacks.js CHANGED
@@ -32,6 +32,7 @@ const BFG = koffi.struct('BFG', {
32
32
  const SimpleCallback = koffi.callback('int SimpleCallback(const char *str)');
33
33
  const RecursiveCallback = koffi.callback('RecursiveCallback', 'float', ['int', 'string', 'double']);
34
34
  const BigCallback = koffi.callback('BFG BigCallback(BFG bfg)');
35
+ const ApplyCallback = koffi.callback('int __stdcall ApplyCallback(int a, int b, int c)');
35
36
 
36
37
  main();
37
38
 
@@ -52,6 +53,7 @@ async function test() {
52
53
  const CallJS = lib.func('int CallJS(const char *str, SimpleCallback cb)');
53
54
  const CallRecursiveJS = lib.func('float CallRecursiveJS(int i, RecursiveCallback func)');
54
55
  const ModifyBFG = lib.func('BFG ModifyBFG(int x, double y, const char *str, BigCallback func, _Out_ BFG *p)');
56
+ const ApplyStd = lib.func('int ApplyStd(int a, int b, int c, ApplyCallback func)');
55
57
 
56
58
  // Simple test similar to README example
57
59
  {
@@ -84,4 +86,10 @@ async function test() {
84
86
  assert.deepEqual(bfg, { a: 2, b: 4, c: -25, d: 'New!', e: 54, inner: { f: -10, g: 3 } });
85
87
  assert.deepEqual(out, { a: 2, b: 4, c: -25, d: 'X/Yo!/X', e: 54, inner: { f: 10, g: 3 } });
86
88
  }
89
+
90
+ // Stdcall callbacks
91
+ {
92
+ let ret = ApplyStd(1, 5, 9, (a, b, c) => a + b * c);
93
+ assert.equal(ret, 46);
94
+ }
87
95
  }
package/test/misc.c CHANGED
@@ -504,3 +504,11 @@ EXPORT BFG ModifyBFG(int x, double y, const char *str, BFG (*func)(BFG bfg), BFG
504
504
  bfg = func(bfg);
505
505
  return bfg;
506
506
  }
507
+
508
+ typedef int STDCALL ApplyCallback(int a, int b, int c);
509
+
510
+ EXPORT int ApplyStd(int a, int b, int c, ApplyCallback *func)
511
+ {
512
+ int ret = func(a, b, c);
513
+ return ret;
514
+ }