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.
- package/CHANGELOG.md +15 -0
- package/build/koffi/darwin_arm64/koffi.node +0 -0
- package/build/koffi/darwin_x64/koffi.node +0 -0
- package/build/koffi/freebsd_arm64/koffi.node +0 -0
- package/build/koffi/freebsd_ia32/koffi.node +0 -0
- package/build/koffi/freebsd_x64/koffi.node +0 -0
- package/build/koffi/linux_arm64/koffi.node +0 -0
- package/build/koffi/linux_armhf/koffi.node +0 -0
- package/build/koffi/linux_ia32/koffi.node +0 -0
- package/build/koffi/linux_loong64/koffi.node +0 -0
- package/build/koffi/linux_riscv64d/koffi.node +0 -0
- package/build/koffi/linux_x64/koffi.node +0 -0
- package/build/koffi/musl_arm64/koffi.node +0 -0
- package/build/koffi/musl_x64/koffi.node +0 -0
- package/build/koffi/openbsd_ia32/koffi.node +0 -0
- package/build/koffi/openbsd_x64/koffi.node +0 -0
- package/build/koffi/win32_arm64/koffi.node +0 -0
- package/build/koffi/win32_ia32/koffi.node +0 -0
- package/build/koffi/win32_x64/koffi.node +0 -0
- package/index.js +8 -8
- package/indirect.js +8 -8
- package/package.json +1 -1
- package/src/koffi/src/abi_arm32.cc +7 -14
- package/src/koffi/src/abi_arm32_asm.S +6 -10
- package/src/koffi/src/abi_arm64.cc +11 -17
- package/src/koffi/src/abi_arm64_asm.S +4 -7
- package/src/koffi/src/abi_arm64_asm.asm +5 -7
- package/src/koffi/src/abi_loong64_asm.S +4 -7
- package/src/koffi/src/abi_riscv64.cc +7 -14
- package/src/koffi/src/abi_riscv64_asm.S +4 -7
- package/src/koffi/src/abi_x64_sysv.cc +7 -14
- package/src/koffi/src/abi_x64_sysv_asm.S +4 -7
- package/src/koffi/src/abi_x64_win.cc +7 -14
- package/src/koffi/src/abi_x64_win_asm.S +29 -24
- package/src/koffi/src/abi_x64_win_asm.asm +28 -25
- package/src/koffi/src/abi_x86.cc +17 -15
- package/src/koffi/src/abi_x86_asm.S +11 -17
- package/src/koffi/src/abi_x86_asm.asm +6 -14
- package/src/koffi/src/call.cc +37 -47
- package/src/koffi/src/call.hh +7 -9
- package/src/koffi/src/ffi.cc +41 -20
- package/src/koffi/src/ffi.hh +1 -1
- package/src/koffi/src/util.cc +7 -11
- package/src/koffi/src/win32.cc +13 -0
- package/src/koffi/src/win32.hh +2 -0
|
@@ -25,10 +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
|
-
extern "C" napi_value CallSwitchStack(Napi::Function *func, size_t argc, napi_value *argv,
|
|
29
|
-
uint8_t *old_sp, Span<uint8_t> *new_stack,
|
|
30
|
-
napi_value (*call)(Napi::Function *func, size_t argc, napi_value *argv));
|
|
31
|
-
|
|
32
28
|
#include "trampolines/prototypes.inc"
|
|
33
29
|
|
|
34
30
|
bool AnalyseFunction(Napi::Env, InstanceData *, FunctionInfo *func)
|
|
@@ -331,8 +327,12 @@ Napi::Value CallData::Complete(const FunctionInfo *func)
|
|
|
331
327
|
K_UNREACHABLE();
|
|
332
328
|
}
|
|
333
329
|
|
|
334
|
-
void CallData::Relay(Size idx, uint8_t *
|
|
330
|
+
void CallData::Relay(Size idx, uint8_t *sp)
|
|
335
331
|
{
|
|
332
|
+
uint8_t *own_sp = sp;
|
|
333
|
+
uint8_t *caller_sp = sp + 128;
|
|
334
|
+
BackRegisters *out_reg = (BackRegisters *)(sp + 64);
|
|
335
|
+
|
|
336
336
|
if (env.IsExceptionPending()) [[unlikely]]
|
|
337
337
|
return;
|
|
338
338
|
|
|
@@ -573,15 +573,8 @@ void CallData::Relay(Size idx, uint8_t *own_sp, uint8_t *caller_sp, bool switch_
|
|
|
573
573
|
|
|
574
574
|
const TypeInfo *type = proto->ret.type;
|
|
575
575
|
|
|
576
|
-
// Make the call
|
|
577
|
-
|
|
578
|
-
if (switch_stack) {
|
|
579
|
-
ret = CallSwitchStack(&func, (size_t)arguments.len, arguments.data, old_sp, &mem->stack,
|
|
580
|
-
[](Napi::Function *func, size_t argc, napi_value *argv) { return (napi_value)func->Call(argv[0], argc - 1, argv + 1); });
|
|
581
|
-
} else {
|
|
582
|
-
ret = (napi_value)func.Call(arguments[0], arguments.len - 1, arguments.data + 1);
|
|
583
|
-
}
|
|
584
|
-
Napi::Value value(env, ret);
|
|
576
|
+
// Make the call!
|
|
577
|
+
Napi::Value value = func.Call(arguments[0], arguments.len - 1, arguments.data + 1);
|
|
585
578
|
|
|
586
579
|
if (env.IsExceptionPending()) [[unlikely]]
|
|
587
580
|
return;
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
.global ForwardCallXF
|
|
14
14
|
.global ForwardCallXD
|
|
15
15
|
|
|
16
|
+
.global SehHandler
|
|
17
|
+
|
|
16
18
|
# Copy function pointer to RAX, in order to save it through argument forwarding.
|
|
17
19
|
# Also make a copy of the SP to CallData::old_sp because the callback system might need it.
|
|
18
20
|
# Save RSP in RBX (non-volatile), and use carefully assembled stack provided by caller.
|
|
@@ -25,16 +27,6 @@
|
|
|
25
27
|
movq %rdx, %rsp
|
|
26
28
|
.endm
|
|
27
29
|
|
|
28
|
-
# Call native function.
|
|
29
|
-
# Once done, restore normal stack pointer and return.
|
|
30
|
-
# The return value is passed untouched through RAX or XMM0.
|
|
31
|
-
.macro epilogue
|
|
32
|
-
call *%rax
|
|
33
|
-
movq %rbp, %rsp
|
|
34
|
-
pop %rbp
|
|
35
|
-
ret
|
|
36
|
-
.endm
|
|
37
|
-
|
|
38
30
|
# Prepare integer argument registers from array passed by caller.
|
|
39
31
|
.macro forward_gpr
|
|
40
32
|
movq 24(%rdx), %r9
|
|
@@ -51,44 +43,62 @@
|
|
|
51
43
|
movsd 0(%rdx), %xmm0
|
|
52
44
|
.endm
|
|
53
45
|
|
|
46
|
+
# CallNative is a minimal wrapper around the native function call.
|
|
47
|
+
# Its frame lives entirely on the custom stack, so its EstablisherFrame passes
|
|
48
|
+
# the TEB stack bounds check. This ensures that SehHandler is found by
|
|
49
|
+
# RtlDispatchException before it tries to cross back to the original stack
|
|
50
|
+
# (through ForwardCall*), which would fail the bounds check and terminate.
|
|
51
|
+
# After the native call returns, CallNative restores the original stack via
|
|
52
|
+
# RBP (non-volatile, preserved by native) and returns directly to the C++ caller.
|
|
53
|
+
CallNative:
|
|
54
|
+
.seh_proc CallNative
|
|
55
|
+
.seh_handler SehHandler, @except
|
|
56
|
+
.seh_endprologue
|
|
57
|
+
call *%rax
|
|
58
|
+
movq %rbp, %rsp
|
|
59
|
+
pop %rbp
|
|
60
|
+
ret
|
|
61
|
+
.seh_endproc
|
|
62
|
+
|
|
54
63
|
ForwardCallG:
|
|
55
64
|
prologue
|
|
56
65
|
forward_gpr
|
|
57
|
-
|
|
66
|
+
jmp CallNative
|
|
58
67
|
|
|
59
68
|
ForwardCallF:
|
|
60
69
|
prologue
|
|
61
70
|
forward_gpr
|
|
62
|
-
|
|
71
|
+
jmp CallNative
|
|
63
72
|
|
|
64
73
|
ForwardCallD:
|
|
65
74
|
prologue
|
|
66
75
|
forward_gpr
|
|
67
|
-
|
|
76
|
+
jmp CallNative
|
|
68
77
|
|
|
69
78
|
ForwardCallXG:
|
|
70
79
|
prologue
|
|
71
80
|
forward_xmm
|
|
72
81
|
forward_gpr
|
|
73
|
-
|
|
82
|
+
jmp CallNative
|
|
74
83
|
|
|
75
84
|
ForwardCallXF:
|
|
76
85
|
prologue
|
|
77
86
|
forward_xmm
|
|
78
87
|
forward_gpr
|
|
79
|
-
|
|
88
|
+
jmp CallNative
|
|
80
89
|
|
|
81
90
|
ForwardCallXD:
|
|
82
91
|
prologue
|
|
83
92
|
forward_xmm
|
|
84
93
|
forward_gpr
|
|
85
|
-
|
|
94
|
+
jmp CallNative
|
|
86
95
|
|
|
87
96
|
# Callbacks
|
|
88
97
|
# ----------------------------
|
|
89
98
|
|
|
90
99
|
.global RelayCallback
|
|
91
|
-
.global
|
|
100
|
+
.global SwitchAndRelay
|
|
101
|
+
.global RelayDirect
|
|
92
102
|
|
|
93
103
|
# First, make a copy of the GPR argument registers (rcx, rdx, r8, r9).
|
|
94
104
|
# Then call the C function RelayCallback with the following arguments:
|
|
@@ -104,8 +114,6 @@ ForwardCallXD:
|
|
|
104
114
|
movq %r9, 56(%rsp)
|
|
105
115
|
movq $\id, %rcx
|
|
106
116
|
leaq 32(%rsp), %rdx
|
|
107
|
-
leaq 160(%rsp), %r8
|
|
108
|
-
leaq 96(%rsp), %r9
|
|
109
117
|
call RelayCallback
|
|
110
118
|
movq 96(%rsp), %rax
|
|
111
119
|
addq $120, %rsp
|
|
@@ -126,8 +134,6 @@ ForwardCallXD:
|
|
|
126
134
|
movsd %xmm3, 88(%rsp)
|
|
127
135
|
movq $\id, %rcx
|
|
128
136
|
leaq 32(%rsp), %rdx
|
|
129
|
-
leaq 160(%rsp), %r8
|
|
130
|
-
leaq 96(%rsp), %r9
|
|
131
137
|
call RelayCallback
|
|
132
138
|
movq 96(%rsp), %rax
|
|
133
139
|
movsd 104(%rsp), %xmm0
|
|
@@ -140,18 +146,17 @@ ForwardCallXD:
|
|
|
140
146
|
# probably misdetect this as a "stack overflow". We have to restore the old
|
|
141
147
|
# stack pointer, call Node.js/V8 and go back to ours.
|
|
142
148
|
# The first three parameters (rcx, rdx, r8) are passed through untouched.
|
|
143
|
-
|
|
149
|
+
SwitchAndRelay:
|
|
144
150
|
endbr64
|
|
145
151
|
push %rbp
|
|
146
152
|
movq %rsp, %rbp
|
|
147
|
-
movq 56(%rsp), %rax
|
|
148
153
|
movq %rsp, %r10
|
|
149
154
|
movq 48(%rsp), %r11
|
|
150
155
|
subq 0(%r11), %r10
|
|
151
156
|
andq $-16, %r10
|
|
152
157
|
movq %r10, 8(%r11)
|
|
153
158
|
leaq -32(%r9), %rsp
|
|
154
|
-
call
|
|
159
|
+
call RelayDirect
|
|
155
160
|
movq %rbp, %rsp
|
|
156
161
|
pop %rbp
|
|
157
162
|
ret
|
|
@@ -15,6 +15,8 @@ public ForwardCallXG
|
|
|
15
15
|
public ForwardCallXF
|
|
16
16
|
public ForwardCallXD
|
|
17
17
|
|
|
18
|
+
extern SehHandler : PROC
|
|
19
|
+
|
|
18
20
|
.code
|
|
19
21
|
|
|
20
22
|
; Copy function pointer to RAX, in order to save it through argument forwarding.
|
|
@@ -32,16 +34,6 @@ prologue macro
|
|
|
32
34
|
mov rsp, rdx
|
|
33
35
|
endm
|
|
34
36
|
|
|
35
|
-
; Call native function.
|
|
36
|
-
; Once done, restore normal stack pointer and return.
|
|
37
|
-
; The return value is passed untouched through RAX or XMM0.
|
|
38
|
-
epilogue macro
|
|
39
|
-
call rax
|
|
40
|
-
mov rsp, rbp
|
|
41
|
-
pop rbp
|
|
42
|
-
ret
|
|
43
|
-
endm
|
|
44
|
-
|
|
45
37
|
; Prepare integer argument registers from array passed by caller.
|
|
46
38
|
forward_gpr macro
|
|
47
39
|
mov r9, qword ptr [rdx+24]
|
|
@@ -58,50 +50,66 @@ forward_xmm macro
|
|
|
58
50
|
movsd xmm0, qword ptr [rdx+0]
|
|
59
51
|
endm
|
|
60
52
|
|
|
53
|
+
; CallNative is a minimal wrapper around the native function call.
|
|
54
|
+
; Its frame lives entirely on the custom stack, so its EstablisherFrame passes
|
|
55
|
+
; the TEB stack bounds check. This ensures that SehHandler is found by
|
|
56
|
+
; RtlDispatchException before it tries to cross back to the original stack
|
|
57
|
+
; (through ForwardCall*), which would fail the bounds check and terminate.
|
|
58
|
+
; After the native call returns, CallNative restores the original stack via
|
|
59
|
+
; RBP (non-volatile, preserved by native) and returns directly to the C++ caller.
|
|
60
|
+
CallNative proc frame:SehHandler
|
|
61
|
+
.endprolog
|
|
62
|
+
call rax
|
|
63
|
+
mov rsp, rbp
|
|
64
|
+
pop rbp
|
|
65
|
+
ret
|
|
66
|
+
CallNative endp
|
|
67
|
+
|
|
61
68
|
ForwardCallG proc frame
|
|
62
69
|
prologue
|
|
63
70
|
forward_gpr
|
|
64
|
-
|
|
71
|
+
jmp CallNative
|
|
65
72
|
ForwardCallG endp
|
|
66
73
|
|
|
67
74
|
ForwardCallF proc frame
|
|
68
75
|
prologue
|
|
69
76
|
forward_gpr
|
|
70
|
-
|
|
77
|
+
jmp CallNative
|
|
71
78
|
ForwardCallF endp
|
|
72
79
|
|
|
73
80
|
ForwardCallD proc frame
|
|
74
81
|
prologue
|
|
75
82
|
forward_gpr
|
|
76
|
-
|
|
83
|
+
jmp CallNative
|
|
77
84
|
ForwardCallD endp
|
|
78
85
|
|
|
79
86
|
ForwardCallXG proc frame
|
|
80
87
|
prologue
|
|
81
88
|
forward_xmm
|
|
82
89
|
forward_gpr
|
|
83
|
-
|
|
90
|
+
jmp CallNative
|
|
84
91
|
ForwardCallXG endp
|
|
85
92
|
|
|
86
93
|
ForwardCallXF proc frame
|
|
87
94
|
prologue
|
|
88
95
|
forward_xmm
|
|
89
96
|
forward_gpr
|
|
90
|
-
|
|
97
|
+
jmp CallNative
|
|
91
98
|
ForwardCallXF endp
|
|
92
99
|
|
|
93
100
|
ForwardCallXD proc frame
|
|
94
101
|
prologue
|
|
95
102
|
forward_xmm
|
|
96
103
|
forward_gpr
|
|
97
|
-
|
|
104
|
+
jmp CallNative
|
|
98
105
|
ForwardCallXD endp
|
|
99
106
|
|
|
100
107
|
; Callbacks
|
|
101
108
|
; ----------------------------
|
|
102
109
|
|
|
103
110
|
extern RelayCallback : PROC
|
|
104
|
-
public
|
|
111
|
+
public SwitchAndRelay
|
|
112
|
+
extern RelayDirect : PROC
|
|
105
113
|
|
|
106
114
|
; First, make a copy of the GPR argument registers (rcx, rdx, r8, r9).
|
|
107
115
|
; Then call the C function RelayCallback with the following arguments:
|
|
@@ -119,8 +127,6 @@ trampoline macro ID
|
|
|
119
127
|
mov qword ptr [rsp+56], r9
|
|
120
128
|
mov rcx, ID
|
|
121
129
|
lea rdx, qword ptr [rsp+32]
|
|
122
|
-
lea r8, qword ptr [rsp+160]
|
|
123
|
-
lea r9, qword ptr [rsp+96]
|
|
124
130
|
call RelayCallback
|
|
125
131
|
mov rax, qword ptr [rsp+96]
|
|
126
132
|
add rsp, 120
|
|
@@ -143,8 +149,6 @@ trampoline_vec macro ID
|
|
|
143
149
|
movsd qword ptr [rsp+88], xmm3
|
|
144
150
|
mov rcx, ID
|
|
145
151
|
lea rdx, qword ptr [rsp+32]
|
|
146
|
-
lea r8, qword ptr [rsp+160]
|
|
147
|
-
lea r9, qword ptr [rsp+96]
|
|
148
152
|
call RelayCallback
|
|
149
153
|
mov rax, qword ptr [rsp+96]
|
|
150
154
|
movsd xmm0, qword ptr [rsp+104]
|
|
@@ -157,25 +161,24 @@ endm
|
|
|
157
161
|
; probably misdetect this as a "stack overflow". We have to restore the old
|
|
158
162
|
; stack pointer, call Node.js/V8 and go back to ours.
|
|
159
163
|
; The first three parameters (rcx, rdx, r8) are passed through untouched.
|
|
160
|
-
|
|
164
|
+
SwitchAndRelay proc frame
|
|
161
165
|
endbr64
|
|
162
166
|
push rbp
|
|
163
167
|
.pushreg rbp
|
|
164
168
|
mov rbp, rsp
|
|
165
169
|
.setframe rbp, 0
|
|
166
170
|
.endprolog
|
|
167
|
-
mov rax, qword ptr [rsp+56]
|
|
168
171
|
mov r10, rsp
|
|
169
172
|
mov r11, qword ptr [rsp+48]
|
|
170
173
|
sub r10, qword ptr [r11+0]
|
|
171
174
|
and r10, -16
|
|
172
175
|
mov qword ptr [r11+8], r10
|
|
173
176
|
lea rsp, [r9-32]
|
|
174
|
-
call
|
|
177
|
+
call RelayDirect
|
|
175
178
|
mov rsp, rbp
|
|
176
179
|
pop rbp
|
|
177
180
|
ret
|
|
178
|
-
|
|
181
|
+
SwitchAndRelay endp
|
|
179
182
|
|
|
180
183
|
; Trampolines
|
|
181
184
|
; ----------------------------
|
package/src/koffi/src/abi_x86.cc
CHANGED
|
@@ -26,6 +26,13 @@ struct BackRegisters {
|
|
|
26
26
|
int ret_pop;
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
+
#if defined(_WIN32)
|
|
30
|
+
struct SehFrame {
|
|
31
|
+
void *Next;
|
|
32
|
+
void *Handler;
|
|
33
|
+
};
|
|
34
|
+
#endif
|
|
35
|
+
|
|
29
36
|
extern "C" uint64_t ForwardCallG(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
30
37
|
extern "C" float ForwardCallF(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
31
38
|
extern "C" double ForwardCallD(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
@@ -33,10 +40,6 @@ extern "C" uint64_t ForwardCallRG(const void *func, uint8_t *sp, uint8_t **out_o
|
|
|
33
40
|
extern "C" float ForwardCallRF(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
34
41
|
extern "C" double ForwardCallRD(const void *func, uint8_t *sp, uint8_t **out_old_sp);
|
|
35
42
|
|
|
36
|
-
extern "C" napi_value CallSwitchStack(Napi::Function *func, size_t argc, napi_value *argv,
|
|
37
|
-
uint8_t *old_sp, Span<uint8_t> *new_stack,
|
|
38
|
-
napi_value (*call)(Napi::Function *func, size_t argc, napi_value *argv));
|
|
39
|
-
|
|
40
43
|
#include "trampolines/prototypes.inc"
|
|
41
44
|
|
|
42
45
|
bool AnalyseFunction(Napi::Env env, InstanceData *instance, FunctionInfo *func)
|
|
@@ -300,6 +303,7 @@ void CallData::Execute(const FunctionInfo *func, void *native)
|
|
|
300
303
|
{
|
|
301
304
|
#if defined(_WIN32)
|
|
302
305
|
TEB *teb = GetTEB();
|
|
306
|
+
SehFrame *seh = (SehFrame *)mem->stack.ptr;
|
|
303
307
|
|
|
304
308
|
// Restore previous stack limits at the end
|
|
305
309
|
K_DEFER_C(exception_list = teb->ExceptionList,
|
|
@@ -319,7 +323,9 @@ void CallData::Execute(const FunctionInfo *func, void *native)
|
|
|
319
323
|
};
|
|
320
324
|
|
|
321
325
|
// Adjust stack limits so SEH works correctly
|
|
322
|
-
|
|
326
|
+
seh->Next = (void *)-1; \
|
|
327
|
+
seh->Handler = (void *)SehHandler; \
|
|
328
|
+
teb->ExceptionList = seh; \
|
|
323
329
|
teb->StackBase = mem->stack0.end();
|
|
324
330
|
teb->StackLimit = mem->stack0.ptr;
|
|
325
331
|
teb->DeallocationStack = mem->stack0.ptr;
|
|
@@ -445,8 +451,11 @@ Napi::Value CallData::Complete(const FunctionInfo *func)
|
|
|
445
451
|
K_UNREACHABLE();
|
|
446
452
|
}
|
|
447
453
|
|
|
448
|
-
void CallData::Relay(Size idx, uint8_t
|
|
454
|
+
void CallData::Relay(Size idx, uint8_t *sp)
|
|
449
455
|
{
|
|
456
|
+
uint8_t *caller_sp = sp + 48;
|
|
457
|
+
BackRegisters *out_reg = (BackRegisters *)(sp + 16);
|
|
458
|
+
|
|
450
459
|
if (env.IsExceptionPending()) [[unlikely]]
|
|
451
460
|
return;
|
|
452
461
|
|
|
@@ -685,15 +694,8 @@ void CallData::Relay(Size idx, uint8_t *, uint8_t *caller_sp, bool switch_stack,
|
|
|
685
694
|
|
|
686
695
|
const TypeInfo *type = proto->ret.type;
|
|
687
696
|
|
|
688
|
-
// Make the call
|
|
689
|
-
|
|
690
|
-
if (switch_stack) {
|
|
691
|
-
ret = CallSwitchStack(&func, (size_t)arguments.len, arguments.data, old_sp, &mem->stack,
|
|
692
|
-
[](Napi::Function *func, size_t argc, napi_value *argv) { return (napi_value)func->Call(argv[0], argc - 1, argv + 1); });
|
|
693
|
-
} else {
|
|
694
|
-
ret = (napi_value)func.Call(arguments[0], arguments.len - 1, arguments.data + 1);
|
|
695
|
-
}
|
|
696
|
-
Napi::Value value(env, ret);
|
|
697
|
+
// Make the call!
|
|
698
|
+
Napi::Value value = func.Call(arguments[0], arguments.len - 1, arguments.data + 1);
|
|
697
699
|
|
|
698
700
|
if (env.IsExceptionPending()) [[unlikely]]
|
|
699
701
|
return;
|
|
@@ -81,7 +81,8 @@ ForwardCallRD:
|
|
|
81
81
|
# ----------------------------
|
|
82
82
|
|
|
83
83
|
.global RelayCallback
|
|
84
|
-
.global
|
|
84
|
+
.global SwitchAndRelay
|
|
85
|
+
.global RelayDirect
|
|
85
86
|
|
|
86
87
|
# Call the C function RelayCallback with the following arguments:
|
|
87
88
|
# static trampoline ID, the current stack pointer, a pointer to the stack arguments of this call,
|
|
@@ -98,10 +99,6 @@ ForwardCallRD:
|
|
|
98
99
|
.cfi_def_cfa esp, 48
|
|
99
100
|
movl $\id, 0(%esp)
|
|
100
101
|
movl %esp, 4(%esp)
|
|
101
|
-
leal 48(%esp), %eax
|
|
102
|
-
movl %eax, 8(%esp)
|
|
103
|
-
leal 16(%esp), %eax
|
|
104
|
-
movl %eax, 12(%esp)
|
|
105
102
|
call GetEIP
|
|
106
103
|
addl $_GLOBAL_OFFSET_TABLE_, %ecx
|
|
107
104
|
call *RelayCallback@GOT(%ecx)
|
|
@@ -126,10 +123,6 @@ ForwardCallRD:
|
|
|
126
123
|
.cfi_def_cfa esp, 48
|
|
127
124
|
movl $\id, 0(%esp)
|
|
128
125
|
movl %esp, 4(%esp)
|
|
129
|
-
leal 48(%esp), %eax
|
|
130
|
-
movl %eax, 8(%esp)
|
|
131
|
-
leal 16(%esp), %eax
|
|
132
|
-
movl %eax, 12(%esp)
|
|
133
126
|
call GetEIP
|
|
134
127
|
addl $_GLOBAL_OFFSET_TABLE_, %ecx
|
|
135
128
|
call *RelayCallback@GOT(%ecx)
|
|
@@ -151,15 +144,11 @@ ForwardCallRD:
|
|
|
151
144
|
.cfi_endproc
|
|
152
145
|
.endm
|
|
153
146
|
|
|
154
|
-
GetEIP:
|
|
155
|
-
movl (%esp), %ecx
|
|
156
|
-
ret
|
|
157
|
-
|
|
158
147
|
# When a callback is relayed, Koffi will call into Node.js and V8 to execute Javascript.
|
|
159
148
|
# The problem is that we're still running on the separate Koffi stack, and V8 will
|
|
160
149
|
# probably misdetect this as a "stack overflow". We have to restore the old
|
|
161
150
|
# stack pointer, call Node.js/V8 and go back to ours.
|
|
162
|
-
|
|
151
|
+
SwitchAndRelay:
|
|
163
152
|
.cfi_startproc
|
|
164
153
|
.cfi_def_cfa esp, 4
|
|
165
154
|
ENDBR32
|
|
@@ -167,21 +156,22 @@ CallSwitchStack:
|
|
|
167
156
|
.cfi_def_cfa esp, 8
|
|
168
157
|
movl %esp, %ebp
|
|
169
158
|
.cfi_def_cfa ebp, 8
|
|
170
|
-
movl 28(%esp), %edx
|
|
171
159
|
movl 24(%esp), %ecx
|
|
172
160
|
movl %esp, %eax
|
|
173
161
|
subl 0(%ecx), %eax
|
|
174
162
|
andl $-16, %eax
|
|
175
163
|
movl %eax, 4(%ecx)
|
|
176
164
|
movl 20(%esp), %esp
|
|
177
|
-
subl $
|
|
165
|
+
subl $24, %esp
|
|
178
166
|
movl 8(%ebp), %eax
|
|
179
167
|
movl %eax, 0(%esp)
|
|
180
168
|
movl 12(%ebp), %eax
|
|
181
169
|
movl %eax, 4(%esp)
|
|
182
170
|
movl 16(%ebp), %eax
|
|
183
171
|
movl %eax, 8(%esp)
|
|
184
|
-
call
|
|
172
|
+
call GetEIP
|
|
173
|
+
addl $_GLOBAL_OFFSET_TABLE_, %ecx
|
|
174
|
+
call *RelayDirect@GOT(%ecx)
|
|
185
175
|
mov %ebp, %esp
|
|
186
176
|
.cfi_def_cfa esp, 8
|
|
187
177
|
pop %ebp
|
|
@@ -189,6 +179,10 @@ CallSwitchStack:
|
|
|
189
179
|
ret
|
|
190
180
|
.cfi_endproc
|
|
191
181
|
|
|
182
|
+
GetEIP:
|
|
183
|
+
movl (%esp), %ecx
|
|
184
|
+
ret
|
|
185
|
+
|
|
192
186
|
# Trampolines
|
|
193
187
|
# ----------------------------
|
|
194
188
|
|
|
@@ -80,7 +80,8 @@ ForwardCallRD endp
|
|
|
80
80
|
; ----------------------------
|
|
81
81
|
|
|
82
82
|
extern RelayCallback : PROC
|
|
83
|
-
public
|
|
83
|
+
public SwitchAndRelay
|
|
84
|
+
extern RelayDirect : PROC
|
|
84
85
|
|
|
85
86
|
; Call the C function RelayCallback with the following arguments:
|
|
86
87
|
; static trampoline ID, the current stack pointer, a pointer to the stack arguments of this call,
|
|
@@ -94,10 +95,6 @@ trampoline macro ID
|
|
|
94
95
|
sub esp, 44
|
|
95
96
|
mov dword ptr [esp+0], ID
|
|
96
97
|
mov dword ptr [esp+4], esp
|
|
97
|
-
lea eax, dword ptr [esp+48]
|
|
98
|
-
mov dword ptr [esp+8], eax
|
|
99
|
-
lea eax, dword ptr [esp+16]
|
|
100
|
-
mov dword ptr [esp+12], eax
|
|
101
98
|
call RelayCallback
|
|
102
99
|
mov edx, dword ptr [esp+44]
|
|
103
100
|
mov ecx, dword ptr [esp+36]
|
|
@@ -117,10 +114,6 @@ trampoline_vec macro ID
|
|
|
117
114
|
sub esp, 44
|
|
118
115
|
mov dword ptr [esp+0], ID
|
|
119
116
|
mov dword ptr [esp+4], esp
|
|
120
|
-
lea eax, dword ptr [esp+48]
|
|
121
|
-
mov dword ptr [esp+8], eax
|
|
122
|
-
lea eax, dword ptr [esp+16]
|
|
123
|
-
mov dword ptr [esp+12], eax
|
|
124
117
|
call RelayCallback
|
|
125
118
|
mov edx, dword ptr [esp+44]
|
|
126
119
|
mov ecx, dword ptr [esp+36]
|
|
@@ -141,29 +134,28 @@ endm
|
|
|
141
134
|
; The problem is that we're still running on the separate Koffi stack, and V8 will
|
|
142
135
|
; probably misdetect this as a "stack overflow". We have to restore the old
|
|
143
136
|
; stack pointer, call Node.js/V8 and go back to ours.
|
|
144
|
-
|
|
137
|
+
SwitchAndRelay proc
|
|
145
138
|
endbr32
|
|
146
139
|
push ebp
|
|
147
140
|
mov ebp, esp
|
|
148
|
-
mov edx, dword ptr [esp+28]
|
|
149
141
|
mov ecx, dword ptr [esp+24]
|
|
150
142
|
mov eax, esp
|
|
151
143
|
sub eax, dword ptr [ecx+0]
|
|
152
144
|
and eax, -16
|
|
153
145
|
mov dword ptr [ecx+4], eax
|
|
154
146
|
mov esp, dword ptr [esp+20]
|
|
155
|
-
sub esp,
|
|
147
|
+
sub esp, 24
|
|
156
148
|
mov eax, dword ptr [ebp+8]
|
|
157
149
|
mov dword ptr [esp+0], eax
|
|
158
150
|
mov eax, dword ptr [ebp+12]
|
|
159
151
|
mov dword ptr [esp+4], eax
|
|
160
152
|
mov eax, dword ptr [ebp+16]
|
|
161
153
|
mov dword ptr [esp+8], eax
|
|
162
|
-
call
|
|
154
|
+
call RelayDirect
|
|
163
155
|
mov esp, ebp
|
|
164
156
|
pop ebp
|
|
165
157
|
ret
|
|
166
|
-
|
|
158
|
+
SwitchAndRelay endp
|
|
167
159
|
|
|
168
160
|
; Trampolines
|
|
169
161
|
; ----------------------------
|
package/src/koffi/src/call.cc
CHANGED
|
@@ -12,15 +12,12 @@ namespace K {
|
|
|
12
12
|
|
|
13
13
|
struct RelayContext {
|
|
14
14
|
CallData *call;
|
|
15
|
-
bool dispose_call;
|
|
16
15
|
|
|
17
16
|
Size idx;
|
|
18
|
-
uint8_t *
|
|
19
|
-
uint8_t *caller_sp;
|
|
20
|
-
BackRegisters *out_reg;
|
|
17
|
+
uint8_t *sp;
|
|
21
18
|
|
|
22
|
-
std::mutex mutex;
|
|
23
|
-
std::condition_variable cv;
|
|
19
|
+
std::mutex mutex = {};
|
|
20
|
+
std::condition_variable cv = {};
|
|
24
21
|
bool done = false;
|
|
25
22
|
};
|
|
26
23
|
|
|
@@ -32,7 +29,6 @@ CallData::CallData(Napi::Env env, InstanceData *instance, InstanceMemory *mem)
|
|
|
32
29
|
mem->depth++;
|
|
33
30
|
|
|
34
31
|
K_ASSERT(AlignUp(mem->stack.ptr, 16) == mem->stack.ptr);
|
|
35
|
-
K_ASSERT(AlignUp(mem->stack.end(), 16) == mem->stack.end());
|
|
36
32
|
}
|
|
37
33
|
|
|
38
34
|
CallData::~CallData()
|
|
@@ -75,50 +71,26 @@ void CallData::Dispose()
|
|
|
75
71
|
instance = nullptr;
|
|
76
72
|
}
|
|
77
73
|
|
|
78
|
-
void CallData::
|
|
74
|
+
void CallData::RelayAsync(Size idx, uint8_t *sp)
|
|
79
75
|
{
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
// to the JS event loop.
|
|
76
|
+
// JS/V8 is single-threaded, and runs on main_thread_id. Forward the call
|
|
77
|
+
// to the JS event loop.
|
|
83
78
|
|
|
84
|
-
|
|
79
|
+
RelayContext ctx = {
|
|
80
|
+
.call = this,
|
|
81
|
+
.idx = idx,
|
|
82
|
+
.sp = sp
|
|
83
|
+
};
|
|
85
84
|
|
|
86
|
-
|
|
87
|
-
ctx.dispose_call = outside_call;
|
|
88
|
-
ctx.idx = idx;
|
|
89
|
-
ctx.own_sp = own_sp;
|
|
90
|
-
ctx.caller_sp = caller_sp;
|
|
91
|
-
ctx.out_reg = out_reg;
|
|
85
|
+
napi_call_threadsafe_function(instance->broker, &ctx, napi_tsfn_blocking);
|
|
92
86
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
while (!ctx.done) {
|
|
98
|
-
ctx.cv.wait(lock);
|
|
99
|
-
}
|
|
100
|
-
} else {
|
|
101
|
-
Napi::HandleScope scope(env);
|
|
102
|
-
Relay(idx, own_sp, caller_sp, !outside_call, out_reg);
|
|
87
|
+
// Wait until it executes
|
|
88
|
+
std::unique_lock<std::mutex> lock(ctx.mutex);
|
|
89
|
+
while (!ctx.done) {
|
|
90
|
+
ctx.cv.wait(lock);
|
|
103
91
|
}
|
|
104
92
|
}
|
|
105
93
|
|
|
106
|
-
void CallData::RelayAsync(napi_env, napi_value, void *, void *udata)
|
|
107
|
-
{
|
|
108
|
-
RelayContext *ctx = (RelayContext *)udata;
|
|
109
|
-
|
|
110
|
-
ctx->call->Relay(ctx->idx, ctx->own_sp, ctx->caller_sp, false, ctx->out_reg);
|
|
111
|
-
|
|
112
|
-
if (ctx->dispose_call) {
|
|
113
|
-
ctx->call->Dispose();
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// We're done!
|
|
117
|
-
std::lock_guard<std::mutex> lock(ctx->mutex);
|
|
118
|
-
ctx->done = true;
|
|
119
|
-
ctx->cv.notify_one();
|
|
120
|
-
}
|
|
121
|
-
|
|
122
94
|
bool CallData::PushString(Napi::Value value, int directions, const char **out_str)
|
|
123
95
|
{
|
|
124
96
|
// Fast path
|
|
@@ -189,7 +161,7 @@ Size CallData::PushStringValue(Napi::Value value, const char **out_str)
|
|
|
189
161
|
K_ASSERT(status == napi_ok);
|
|
190
162
|
|
|
191
163
|
len++;
|
|
192
|
-
buf = AllocateSpan<char>(&
|
|
164
|
+
buf = AllocateSpan<char>(&alloc, (Size)len);
|
|
193
165
|
|
|
194
166
|
status = napi_get_value_string_utf8(env, value, buf.ptr, (size_t)buf.len, &len);
|
|
195
167
|
K_ASSERT(status == napi_ok);
|
|
@@ -224,7 +196,7 @@ Size CallData::PushString16Value(Napi::Value value, const char16_t **out_str16)
|
|
|
224
196
|
K_ASSERT(status == napi_ok);
|
|
225
197
|
|
|
226
198
|
len++;
|
|
227
|
-
buf = AllocateSpan<char16_t>(&
|
|
199
|
+
buf = AllocateSpan<char16_t>(&alloc, (Size)len);
|
|
228
200
|
|
|
229
201
|
status = napi_get_value_string_utf16(env, value, buf.ptr, (size_t)buf.len, &len);
|
|
230
202
|
K_ASSERT(status == napi_ok);
|
|
@@ -255,7 +227,7 @@ Size CallData::PushString32Value(Napi::Value value, const char32_t **out_str32)
|
|
|
255
227
|
mem->heap.ptr += buf16.len * 4;
|
|
256
228
|
mem->heap.len -= buf16.len * 4;
|
|
257
229
|
} else {
|
|
258
|
-
buf = AllocateSpan<char32_t>(&
|
|
230
|
+
buf = AllocateSpan<char32_t>(&alloc, buf16.len);
|
|
259
231
|
}
|
|
260
232
|
|
|
261
233
|
Size j = 0;
|
|
@@ -1315,4 +1287,22 @@ void CallData::PopOutArguments()
|
|
|
1315
1287
|
}
|
|
1316
1288
|
}
|
|
1317
1289
|
|
|
1290
|
+
void PerformAsyncRelay(napi_env, napi_value, void *, void *udata)
|
|
1291
|
+
{
|
|
1292
|
+
RelayContext *ctx = (RelayContext *)udata;
|
|
1293
|
+
CallData *call = ctx->call;
|
|
1294
|
+
|
|
1295
|
+
call->Relay(ctx->idx, ctx->sp);
|
|
1296
|
+
|
|
1297
|
+
// This CallData was created artificially just to perform the callback. Which means the
|
|
1298
|
+
// creator may not run on the main thread, and cannot properly destroy it, because some
|
|
1299
|
+
// members are managed by Node.
|
|
1300
|
+
call->Dispose();
|
|
1301
|
+
|
|
1302
|
+
// We're done!
|
|
1303
|
+
std::lock_guard<std::mutex> lock(ctx->mutex);
|
|
1304
|
+
ctx->done = true;
|
|
1305
|
+
ctx->cv.notify_one();
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1318
1308
|
}
|