koffi 2.15.3 → 2.15.5

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 (46) hide show
  1. package/CHANGELOG.md +16 -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 +0 -8
  24. package/src/koffi/src/abi_arm32_asm.S +8 -29
  25. package/src/koffi/src/abi_arm64.cc +4 -11
  26. package/src/koffi/src/abi_arm64_asm.S +5 -28
  27. package/src/koffi/src/abi_arm64_asm.asm +6 -21
  28. package/src/koffi/src/abi_loong64_asm.S +5 -23
  29. package/src/koffi/src/abi_riscv64.cc +0 -8
  30. package/src/koffi/src/abi_riscv64_asm.S +5 -23
  31. package/src/koffi/src/abi_x64_sysv.cc +0 -8
  32. package/src/koffi/src/abi_x64_sysv_asm.S +5 -26
  33. package/src/koffi/src/abi_x64_win.cc +0 -8
  34. package/src/koffi/src/abi_x64_win_asm.S +5 -16
  35. package/src/koffi/src/abi_x64_win_asm.asm +7 -19
  36. package/src/koffi/src/abi_x86.cc +17 -13
  37. package/src/koffi/src/abi_x86_asm.S +15 -24
  38. package/src/koffi/src/abi_x86_asm.asm +14 -20
  39. package/src/koffi/src/call.cc +8 -2
  40. package/src/koffi/src/call.hh +1 -1
  41. package/src/koffi/src/ffi.cc +1 -1
  42. package/src/koffi/src/trampolines/armasm.inc +0 -32770
  43. package/src/koffi/src/trampolines/gnu.inc +0 -24578
  44. package/src/koffi/src/trampolines/masm32.inc +0 -32770
  45. package/src/koffi/src/trampolines/masm64.inc +0 -32770
  46. package/src/koffi/src/trampolines/prototypes.inc +16385 -16385
@@ -25,8 +25,6 @@ extern "C" uint64_t ForwardCallXG(const void *func, uint8_t *sp, uint8_t **out_o
25
25
  extern "C" float ForwardCallXF(const void *func, uint8_t *sp, uint8_t **out_old_sp);
26
26
  extern "C" double ForwardCallXD(const void *func, uint8_t *sp, uint8_t **out_old_sp);
27
27
 
28
- #include "trampolines/prototypes.inc"
29
-
30
28
  bool AnalyseFunction(Napi::Env, InstanceData *, FunctionInfo *func)
31
29
  {
32
30
  func->ret.regular = IsRegularSize(func->ret.type->size, 8);
@@ -736,12 +734,6 @@ void CallData::Relay(Size idx, uint8_t *sp)
736
734
  err_guard.Disable();
737
735
  }
738
736
 
739
- void *GetTrampoline(int16_t idx, const FunctionInfo *proto)
740
- {
741
- bool xmm = proto->forward_fp || IsFloat(proto->ret.type);
742
- return Trampolines[idx][xmm];
743
- }
744
-
745
737
  }
746
738
 
747
739
  #endif
@@ -100,28 +100,18 @@ ForwardCallXD:
100
100
  .global SwitchAndRelay
101
101
  .global RelayDirect
102
102
 
103
- # First, make a copy of the GPR argument registers (rcx, rdx, r8, r9).
103
+ # First, make a copy of argument registers.
104
104
  # Then call the C function RelayCallback with the following arguments:
105
105
  # static trampoline ID, a pointer to the saved GPR array, a pointer to the stack
106
106
  # arguments of this call, and a pointer to a struct that will contain the result registers.
107
107
  # After the call, simply load these registers from the output struct.
108
108
  .macro trampoline id
109
109
  endbr64
110
- subq $120, %rsp
111
- movq %rcx, 32(%rsp)
112
- movq %rdx, 40(%rsp)
113
- movq %r8, 48(%rsp)
114
- movq %r9, 56(%rsp)
115
- movq $\id, %rcx
116
- leaq 32(%rsp), %rdx
117
- call RelayCallback
118
- movq 96(%rsp), %rax
119
- addq $120, %rsp
120
- ret
110
+ movq $\id, %rax
111
+ jmp RelayTrampoline
121
112
  .endm
122
113
 
123
- # Same thing, but also forward the XMM argument registers and load the XMM result registers.
124
- .macro trampoline_vec id
114
+ RelayTrampoline:
125
115
  endbr64
126
116
  subq $120, %rsp
127
117
  movq %rcx, 32(%rsp)
@@ -132,14 +122,13 @@ ForwardCallXD:
132
122
  movsd %xmm1, 72(%rsp)
133
123
  movsd %xmm2, 80(%rsp)
134
124
  movsd %xmm3, 88(%rsp)
135
- movq $\id, %rcx
125
+ movq %rax, %rcx
136
126
  leaq 32(%rsp), %rdx
137
127
  call RelayCallback
138
128
  movq 96(%rsp), %rax
139
129
  movsd 104(%rsp), %xmm0
140
130
  addq $120, %rsp
141
131
  ret
142
- .endm
143
132
 
144
133
  # When a callback is relayed, Koffi will call into Node.js and V8 to execute Javascript.
145
134
  # The problem is that we're still running on the separate Koffi stack, and V8 will
@@ -111,31 +111,19 @@ extern RelayCallback : PROC
111
111
  public SwitchAndRelay
112
112
  extern RelayDirect : PROC
113
113
 
114
- ; First, make a copy of the GPR argument registers (rcx, rdx, r8, r9).
114
+ ; First, make a copy of argument registers.
115
115
  ; Then call the C function RelayCallback with the following arguments:
116
116
  ; static trampoline ID, a pointer to the saved GPR array, a pointer to the stack
117
117
  ; arguments of this call, and a pointer to a struct that will contain the result registers.
118
118
  ; After the call, simply load these registers from the output struct.
119
119
  trampoline macro ID
120
- endbr64
121
- sub rsp, 120
122
- .allocstack 120
123
120
  .endprolog
124
- mov qword ptr [rsp+32], rcx
125
- mov qword ptr [rsp+40], rdx
126
- mov qword ptr [rsp+48], r8
127
- mov qword ptr [rsp+56], r9
128
- mov rcx, ID
129
- lea rdx, qword ptr [rsp+32]
130
- call RelayCallback
131
- mov rax, qword ptr [rsp+96]
132
- add rsp, 120
133
- ret
121
+ endbr64
122
+ mov rax, ID
123
+ jmp RelayTrampoline
134
124
  endm
135
125
 
136
- ; Same thing, but also forward the XMM argument registers and load the XMM result registers.
137
- trampoline_vec macro ID
138
- endbr64
126
+ RelayTrampoline proc frame
139
127
  sub rsp, 120
140
128
  .allocstack 120
141
129
  .endprolog
@@ -147,14 +135,14 @@ trampoline_vec macro ID
147
135
  movsd qword ptr [rsp+72], xmm1
148
136
  movsd qword ptr [rsp+80], xmm2
149
137
  movsd qword ptr [rsp+88], xmm3
150
- mov rcx, ID
138
+ mov rcx, rax
151
139
  lea rdx, qword ptr [rsp+32]
152
140
  call RelayCallback
153
141
  mov rax, qword ptr [rsp+96]
154
142
  movsd xmm0, qword ptr [rsp+104]
155
143
  add rsp, 120
156
144
  ret
157
- endm
145
+ RelayTrampoline endp
158
146
 
159
147
  ; When a callback is relayed, Koffi will call into Node.js and V8 to execute Javascript.
160
148
  ; The problem is that we're still running on the separate Koffi stack, and V8 will
@@ -22,7 +22,7 @@ struct BackRegisters {
22
22
  double d;
23
23
  float f;
24
24
  } x87;
25
- bool x87_double;
25
+ int ret_type;
26
26
  int ret_pop;
27
27
  };
28
28
 
@@ -40,8 +40,6 @@ extern "C" uint64_t ForwardCallRG(const void *func, uint8_t *sp, uint8_t **out_o
40
40
  extern "C" float ForwardCallRF(const void *func, uint8_t *sp, uint8_t **out_old_sp);
41
41
  extern "C" double ForwardCallRD(const void *func, uint8_t *sp, uint8_t **out_old_sp);
42
42
 
43
- #include "trampolines/prototypes.inc"
44
-
45
43
  bool AnalyseFunction(Napi::Env env, InstanceData *instance, FunctionInfo *func)
46
44
  {
47
45
  if (!func->lib && func->convention != CallConvention::Cdecl &&
@@ -500,7 +498,7 @@ void CallData::Relay(Size idx, uint8_t *sp)
500
498
  K_DEFER_N(err_guard) {
501
499
  int pop = out_reg->ret_pop;
502
500
  memset(out_reg, 0, K_SIZE(*out_reg));
503
- out_reg->x87_double = true;
501
+ out_reg->ret_type = 0;
504
502
  out_reg->ret_pop = pop;
505
503
  };
506
504
 
@@ -709,6 +707,7 @@ void CallData::Relay(Size idx, uint8_t *sp)
709
707
  \
710
708
  CType v = GetNumber<CType>(value); \
711
709
  out_reg->eax = (uint32_t)v; \
710
+ out_reg->ret_type = 0; \
712
711
  } while (false)
713
712
  #define RETURN_INTEGER_32_SWAP(CType) \
714
713
  do { \
@@ -719,6 +718,7 @@ void CallData::Relay(Size idx, uint8_t *sp)
719
718
  \
720
719
  CType v = GetNumber<CType>(value); \
721
720
  out_reg->eax = (uint32_t)ReverseBytes(v); \
721
+ out_reg->ret_type = 0; \
722
722
  } while (false)
723
723
  #define RETURN_INTEGER_64(CType) \
724
724
  do { \
@@ -731,6 +731,7 @@ void CallData::Relay(Size idx, uint8_t *sp)
731
731
  \
732
732
  out_reg->eax = (uint32_t)((uint64_t)v >> 32); \
733
733
  out_reg->edx = (uint32_t)((uint64_t)v & 0xFFFFFFFFu); \
734
+ out_reg->ret_type = 0; \
734
735
  } while (false)
735
736
  #define RETURN_INTEGER_64_SWAP(CType) \
736
737
  do { \
@@ -743,10 +744,11 @@ void CallData::Relay(Size idx, uint8_t *sp)
743
744
  \
744
745
  out_reg->eax = (uint32_t)((uint64_t)v >> 32); \
745
746
  out_reg->edx = (uint32_t)((uint64_t)v & 0xFFFFFFFFu); \
747
+ out_reg->ret_type = 0; \
746
748
  } while (false)
747
749
 
748
750
  switch (type->primitive) {
749
- case PrimitiveKind::Void: {} break;
751
+ case PrimitiveKind::Void: { out_reg->ret_type = 0; } break;
750
752
  case PrimitiveKind::Bool: {
751
753
  if (!value.IsBoolean()) [[unlikely]] {
752
754
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected boolean", GetValueType(instance, value));
@@ -755,6 +757,7 @@ void CallData::Relay(Size idx, uint8_t *sp)
755
757
 
756
758
  bool b = value.As<Napi::Boolean>();
757
759
  out_reg->eax = (uint32_t)b;
760
+ out_reg->ret_type = 0;
758
761
  } break;
759
762
  case PrimitiveKind::Int8: { RETURN_INTEGER_32(int8_t); } break;
760
763
  case PrimitiveKind::UInt8: { RETURN_INTEGER_32(uint8_t); } break;
@@ -776,6 +779,7 @@ void CallData::Relay(Size idx, uint8_t *sp)
776
779
  return;
777
780
 
778
781
  out_reg->eax = (uint32_t)str;
782
+ out_reg->ret_type = 0;
779
783
  } break;
780
784
  case PrimitiveKind::String16: {
781
785
  const char16_t *str16;
@@ -783,6 +787,7 @@ void CallData::Relay(Size idx, uint8_t *sp)
783
787
  return;
784
788
 
785
789
  out_reg->eax = (uint32_t)str16;
790
+ out_reg->ret_type = 0;
786
791
  } break;
787
792
  case PrimitiveKind::String32: {
788
793
  const char32_t *str32;
@@ -790,6 +795,7 @@ void CallData::Relay(Size idx, uint8_t *sp)
790
795
  return;
791
796
 
792
797
  out_reg->eax = (uint32_t)str32;
798
+ out_reg->ret_type = 0;
793
799
  } break;
794
800
  case PrimitiveKind::Pointer: {
795
801
  uint8_t *ptr;
@@ -812,6 +818,7 @@ void CallData::Relay(Size idx, uint8_t *sp)
812
818
  }
813
819
 
814
820
  out_reg->eax = (uint32_t)ptr;
821
+ out_reg->ret_type = 0;
815
822
  } break;
816
823
  case PrimitiveKind::Record:
817
824
  case PrimitiveKind::Union: {
@@ -829,6 +836,8 @@ void CallData::Relay(Size idx, uint8_t *sp)
829
836
  } else {
830
837
  PushObject(obj, type, (uint8_t *)&out_reg->eax);
831
838
  }
839
+
840
+ out_reg->ret_type = 0;
832
841
  } break;
833
842
  case PrimitiveKind::Array: { K_UNREACHABLE(); } break;
834
843
  case PrimitiveKind::Float32: {
@@ -838,7 +847,7 @@ void CallData::Relay(Size idx, uint8_t *sp)
838
847
  }
839
848
 
840
849
  out_reg->x87.f = GetNumber<float>(value);
841
- out_reg->x87_double = false;
850
+ out_reg->ret_type = 1;
842
851
  } break;
843
852
  case PrimitiveKind::Float64: {
844
853
  if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
@@ -847,7 +856,7 @@ void CallData::Relay(Size idx, uint8_t *sp)
847
856
  }
848
857
 
849
858
  out_reg->x87.d = GetNumber<double>(value);
850
- out_reg->x87_double = true;
859
+ out_reg->ret_type = 2;
851
860
  } break;
852
861
  case PrimitiveKind::Callback: {
853
862
  void *ptr;
@@ -868,6 +877,7 @@ void CallData::Relay(Size idx, uint8_t *sp)
868
877
  }
869
878
 
870
879
  out_reg->eax = (uint32_t)ptr;
880
+ out_reg->ret_type = 0;
871
881
  } break;
872
882
 
873
883
  case PrimitiveKind::Prototype: { K_UNREACHABLE(); } break;
@@ -881,12 +891,6 @@ void CallData::Relay(Size idx, uint8_t *sp)
881
891
  err_guard.Disable();
882
892
  }
883
893
 
884
- void *GetTrampoline(int16_t idx, const FunctionInfo *proto)
885
- {
886
- bool x87 = IsFloat(proto->ret.type);
887
- return Trampolines[idx][x87];
888
- }
889
-
890
894
  }
891
895
 
892
896
  #endif
@@ -91,13 +91,21 @@ ForwardCallRD:
91
91
  # Depending on ABI, call convention and return value size, we need to issue ret <something>. Since ret
92
92
  # only takes an immediate value, and I prefer not to branch, the return address is moved instead according
93
93
  # to BackRegisters::ret_pop before ret is issued.
94
+ # We need to branch at the end to avoid x87 stack imbalance.
94
95
  .macro trampoline id
95
96
  .cfi_startproc
96
- .cfi_def_cfa esp, 4
97
97
  ENDBR32
98
+ movl $\id, %eax
99
+ jmp RelayTrampoline
100
+ .cfi_endproc
101
+ .endm
102
+
103
+ RelayTrampoline:
104
+ .cfi_startproc
105
+ .cfi_def_cfa esp, 4
98
106
  sub $44, %esp
99
107
  .cfi_def_cfa esp, 48
100
- movl $\id, 0(%esp)
108
+ movl %eax, 0(%esp)
101
109
  movl %esp, 4(%esp)
102
110
  call GetEIP
103
111
  addl $_GLOBAL_OFFSET_TABLE_, %ecx
@@ -105,32 +113,16 @@ ForwardCallRD:
105
113
  movl 44(%esp), %edx
106
114
  movl 36(%esp), %ecx
107
115
  movl %edx, 44(%esp, %ecx)
116
+ cmpl $1, 32(%esp)
117
+ je 1f
118
+ cmpl $2, 32(%esp)
119
+ je 2f
120
+ 0:
108
121
  movl 16(%esp), %eax
109
122
  movl 20(%esp), %edx
110
123
  leal 44(%esp, %ecx), %esp
111
124
  .cfi_def_cfa esp, 4
112
125
  ret
113
- .cfi_endproc
114
- .endm
115
-
116
- # This version also loads the x87 stack with the result, if need be.
117
- # We have to branch to avoid x87 stack imbalance.
118
- .macro trampoline_vec id
119
- .cfi_startproc
120
- .cfi_def_cfa esp, 4
121
- ENDBR32
122
- sub $44, %esp
123
- .cfi_def_cfa esp, 48
124
- movl $\id, 0(%esp)
125
- movl %esp, 4(%esp)
126
- call GetEIP
127
- addl $_GLOBAL_OFFSET_TABLE_, %ecx
128
- call *RelayCallback@GOT(%ecx)
129
- movl 44(%esp), %edx
130
- movl 36(%esp), %ecx
131
- movl %edx, 44(%esp, %ecx, 4)
132
- cmpb $0, 32(%esp)
133
- jne 2f
134
126
  1:
135
127
  flds 24(%esp)
136
128
  leal 44(%esp, %ecx), %esp
@@ -142,7 +134,6 @@ ForwardCallRD:
142
134
  .cfi_def_cfa esp, 4
143
135
  ret
144
136
  .cfi_endproc
145
- .endm
146
137
 
147
138
  # When a callback is relayed, Koffi will call into Node.js and V8 to execute Javascript.
148
139
  # The problem is that we're still running on the separate Koffi stack, and V8 will
@@ -90,36 +90,30 @@ extern RelayDirect : PROC
90
90
  ; Depending on ABI, call convention and return value size, we need to issue ret <something>. Since ret
91
91
  ; only takes an immediate value, and I prefer not to branch, the return address is moved instead according
92
92
  ; to BackRegisters::ret_pop before ret is issued.
93
+ ; We need to branch at the end to avoid x87 stack imbalance.
93
94
  trampoline macro ID
94
95
  endbr32
96
+ mov eax, ID
97
+ jmp RelayTrampoline
98
+ endm
99
+
100
+ RelayTrampoline proc
95
101
  sub esp, 44
96
- mov dword ptr [esp+0], ID
102
+ mov dword ptr [esp+0], eax
97
103
  mov dword ptr [esp+4], esp
98
104
  call RelayCallback
99
105
  mov edx, dword ptr [esp+44]
100
106
  mov ecx, dword ptr [esp+36]
101
107
  mov dword ptr [esp+ecx+44], edx
108
+ cmp dword ptr [esp+32], 1
109
+ je l1
110
+ cmp dword ptr [esp+32], 2
111
+ je l2
112
+ l0:
102
113
  mov eax, dword ptr [esp+16]
103
114
  mov edx, dword ptr [esp+20]
104
- lea esp, [esp+ecx+44]
115
+ lea esp, dword ptr [esp+ecx+44]
105
116
  ret
106
- endm
107
-
108
- ; This version also loads the x87 stack with the result, if need be.
109
- ; We have to branch to avoid x87 stack imbalance.
110
- trampoline_vec macro ID
111
- local l1, l2, l3
112
-
113
- endbr32
114
- sub esp, 44
115
- mov dword ptr [esp+0], ID
116
- mov dword ptr [esp+4], esp
117
- call RelayCallback
118
- mov edx, dword ptr [esp+44]
119
- mov ecx, dword ptr [esp+36]
120
- mov dword ptr [esp+ecx+44], edx
121
- cmp byte ptr [esp+32], 0
122
- jne l2
123
117
  l1:
124
118
  fld dword ptr [esp+24]
125
119
  lea esp, dword ptr [esp+ecx+44]
@@ -128,7 +122,7 @@ l2:
128
122
  fld qword ptr [esp+24]
129
123
  lea esp, dword ptr [esp+ecx+44]
130
124
  ret
131
- endm
125
+ RelayTrampoline endp
132
126
 
133
127
  ; When a callback is relayed, Koffi will call into Node.js and V8 to execute Javascript.
134
128
  ; The problem is that we're still running on the separate Koffi stack, and V8 will
@@ -21,6 +21,8 @@ struct RelayContext {
21
21
  bool done = false;
22
22
  };
23
23
 
24
+ #include "trampolines/prototypes.inc"
25
+
24
26
  CallData::CallData(Napi::Env env, InstanceData *instance, InstanceMemory *mem)
25
27
  : env(env), instance(instance),
26
28
  mem(mem), old_stack_mem(mem->stack), old_heap_mem(mem->heap)
@@ -29,7 +31,6 @@ CallData::CallData(Napi::Env env, InstanceData *instance, InstanceMemory *mem)
29
31
  mem->depth++;
30
32
 
31
33
  K_ASSERT(AlignUp(mem->stack.ptr, 16) == mem->stack.ptr);
32
- K_ASSERT(AlignUp(mem->stack.end(), 16) == mem->stack.end());
33
34
  }
34
35
 
35
36
  CallData::~CallData()
@@ -1139,7 +1140,7 @@ void *CallData::ReserveTrampoline(const FunctionInfo *proto, Napi::Function func
1139
1140
  trampoline->recv.Reset();
1140
1141
  trampoline->generation = (int32_t)mem->generation;
1141
1142
 
1142
- void *ptr = GetTrampoline(idx, proto);
1143
+ void *ptr = GetTrampoline(idx);
1143
1144
 
1144
1145
  return ptr;
1145
1146
  }
@@ -1306,4 +1307,9 @@ void PerformAsyncRelay(napi_env, napi_value, void *, void *udata)
1306
1307
  ctx->cv.notify_one();
1307
1308
  }
1308
1309
 
1310
+ void *GetTrampoline(int16_t idx)
1311
+ {
1312
+ return Trampolines[idx];
1313
+ }
1314
+
1309
1315
  }
@@ -174,6 +174,6 @@ inline T *CallData::AllocHeap(Size size, Size align)
174
174
 
175
175
  void PerformAsyncRelay(napi_env env, napi_value callback, void *ctx, void *udata);
176
176
 
177
- void *GetTrampoline(int16_t idx, const FunctionInfo *proto);
177
+ void *GetTrampoline(int16_t idx);
178
178
 
179
179
  }
@@ -2013,7 +2013,7 @@ static Napi::Value RegisterCallback(const Napi::CallbackInfo &info)
2013
2013
  }
2014
2014
  trampoline->generation = -1;
2015
2015
 
2016
- void *ptr = GetTrampoline(idx, type->ref.proto);
2016
+ void *ptr = GetTrampoline(idx);
2017
2017
 
2018
2018
  Napi::External<void> external = Napi::External<void>::New(env, ptr);
2019
2019
  SetValueTag(external, type->ref.marker);