koffi 1.1.5 → 1.2.0-alpha.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.
- package/README.md +47 -3
- package/package.json +2 -3
- package/qemu/registry/machines.json +26 -13
- package/src/abi_arm32.cc +520 -34
- package/src/abi_arm32_fwd.S +237 -22
- package/src/abi_arm64.cc +558 -23
- package/src/abi_arm64_fwd.S +236 -38
- package/src/abi_arm64_fwd.asm +232 -16
- package/src/abi_riscv64.cc +438 -66
- package/src/abi_riscv64_fwd.S +216 -23
- package/src/abi_x64_sysv.cc +449 -77
- package/src/abi_x64_sysv_fwd.S +175 -86
- package/src/abi_x64_win.cc +407 -18
- package/src/abi_x64_win_fwd.asm +215 -0
- package/src/abi_x86.cc +412 -21
- package/src/abi_x86_fwd.S +223 -18
- package/src/abi_x86_fwd.asm +218 -0
- package/src/call.cc +113 -17
- package/src/call.hh +17 -3
- package/src/ffi.cc +142 -103
- package/src/ffi.hh +24 -5
- package/src/parser.cc +1 -1
- package/test/misc.c +74 -0
package/src/abi_x86_fwd.S
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
13
|
|
|
14
14
|
.global ForwardCallG
|
|
15
15
|
.global ForwardCallF
|
|
@@ -18,17 +18,20 @@
|
|
|
18
18
|
.global ForwardCallRF
|
|
19
19
|
.global ForwardCallRD
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
# Copy function pointer to EAX, in order to save it through argument forwarding.
|
|
22
|
+
# Also make a copy of the SP to CallData::old_sp because the callback system might need it.
|
|
23
|
+
# Save ESP in EBX (non-volatile), and use carefully assembled stack provided by caller.
|
|
23
24
|
.macro prologue
|
|
24
25
|
.cfi_startproc
|
|
25
26
|
.cfi_def_cfa esp, 4
|
|
26
27
|
endbr32
|
|
27
28
|
push %ebx
|
|
28
29
|
.cfi_def_cfa esp, 8
|
|
29
|
-
movl 8(%esp), %eax
|
|
30
30
|
movl %esp, %ebx
|
|
31
31
|
.cfi_def_cfa ebx, 8
|
|
32
|
+
movl 16(%esp), %eax
|
|
33
|
+
movl %esp, 0(%eax)
|
|
34
|
+
movl 8(%esp), %eax
|
|
32
35
|
movl 12(%esp), %esp
|
|
33
36
|
.endm
|
|
34
37
|
|
|
@@ -38,9 +41,9 @@
|
|
|
38
41
|
addl $16, %esp
|
|
39
42
|
.endm
|
|
40
43
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
+
# Call native function.
|
|
45
|
+
# Once done, restore normal stack pointer and return.
|
|
46
|
+
# The return value is passed back untouched.
|
|
44
47
|
.macro epilogue
|
|
45
48
|
call *%eax
|
|
46
49
|
movl %ebx, %esp
|
|
@@ -76,3 +79,205 @@ ForwardCallRD:
|
|
|
76
79
|
prologue
|
|
77
80
|
fastcall
|
|
78
81
|
epilogue
|
|
82
|
+
|
|
83
|
+
# Callback trampolines
|
|
84
|
+
# ----------------------------
|
|
85
|
+
|
|
86
|
+
.global Trampoline0
|
|
87
|
+
.global Trampoline1
|
|
88
|
+
.global Trampoline2
|
|
89
|
+
.global Trampoline3
|
|
90
|
+
.global Trampoline4
|
|
91
|
+
.global Trampoline5
|
|
92
|
+
.global Trampoline6
|
|
93
|
+
.global Trampoline7
|
|
94
|
+
.global Trampoline8
|
|
95
|
+
.global Trampoline9
|
|
96
|
+
.global Trampoline10
|
|
97
|
+
.global Trampoline11
|
|
98
|
+
.global Trampoline12
|
|
99
|
+
.global Trampoline13
|
|
100
|
+
.global Trampoline14
|
|
101
|
+
.global Trampoline15
|
|
102
|
+
.global TrampolineX0
|
|
103
|
+
.global TrampolineX1
|
|
104
|
+
.global TrampolineX2
|
|
105
|
+
.global TrampolineX3
|
|
106
|
+
.global TrampolineX4
|
|
107
|
+
.global TrampolineX5
|
|
108
|
+
.global TrampolineX6
|
|
109
|
+
.global TrampolineX7
|
|
110
|
+
.global TrampolineX8
|
|
111
|
+
.global TrampolineX9
|
|
112
|
+
.global TrampolineX10
|
|
113
|
+
.global TrampolineX11
|
|
114
|
+
.global TrampolineX12
|
|
115
|
+
.global TrampolineX13
|
|
116
|
+
.global TrampolineX14
|
|
117
|
+
.global TrampolineX15
|
|
118
|
+
.global RelayCallBack
|
|
119
|
+
.global CallSwitchStack
|
|
120
|
+
|
|
121
|
+
# Call the C function RelayCallBack with the following arguments:
|
|
122
|
+
# static trampoline ID, the current stack pointer, a pointer to the stack arguments of this call,
|
|
123
|
+
# and a pointer to a struct that will contain the result registers.
|
|
124
|
+
# After the call, simply load these registers from the output struct.
|
|
125
|
+
.macro trampoline id
|
|
126
|
+
.cfi_startproc
|
|
127
|
+
.cfi_def_cfa esp, 4
|
|
128
|
+
endbr32
|
|
129
|
+
sub $44, %esp
|
|
130
|
+
.cfi_def_cfa esp, 48
|
|
131
|
+
movl $\id, 0(%esp)
|
|
132
|
+
movl %esp, 4(%esp)
|
|
133
|
+
leal 48(%esp), %eax
|
|
134
|
+
movl %eax, 8(%esp)
|
|
135
|
+
leal 16(%esp), %eax
|
|
136
|
+
movl %eax, 12(%esp)
|
|
137
|
+
call GetEIP
|
|
138
|
+
addl $_GLOBAL_OFFSET_TABLE_, %ecx
|
|
139
|
+
call *RelayCallBack@GOT(%ecx)
|
|
140
|
+
movl 16(%esp), %eax
|
|
141
|
+
movl 20(%esp), %edx
|
|
142
|
+
addl $44, %esp
|
|
143
|
+
.cfi_def_cfa esp, 4
|
|
144
|
+
ret
|
|
145
|
+
.cfi_endproc
|
|
146
|
+
.endm
|
|
147
|
+
|
|
148
|
+
# This version also loads the x87 stack with the result, if need be.
|
|
149
|
+
# We have to branch to avoid x87 stack imbalance.
|
|
150
|
+
.macro trampoline_x87 id
|
|
151
|
+
.cfi_startproc
|
|
152
|
+
.cfi_def_cfa esp, 4
|
|
153
|
+
endbr32
|
|
154
|
+
sub $44, %esp
|
|
155
|
+
.cfi_def_cfa esp, 48
|
|
156
|
+
movl $\id, 0(%esp)
|
|
157
|
+
movl %esp, 4(%esp)
|
|
158
|
+
leal 48(%esp), %eax
|
|
159
|
+
movl %eax, 8(%esp)
|
|
160
|
+
leal 16(%esp), %eax
|
|
161
|
+
movl %eax, 12(%esp)
|
|
162
|
+
call GetEIP
|
|
163
|
+
addl $_GLOBAL_OFFSET_TABLE_, %ecx
|
|
164
|
+
call *RelayCallBack@GOT(%ecx)
|
|
165
|
+
cmpb $1, 36(%esp)
|
|
166
|
+
je 2f
|
|
167
|
+
1:
|
|
168
|
+
flds 32(%esp)
|
|
169
|
+
jmp 3f
|
|
170
|
+
2:
|
|
171
|
+
fldl 24(%esp)
|
|
172
|
+
3:
|
|
173
|
+
movl 16(%esp), %eax
|
|
174
|
+
movl 20(%esp), %edx
|
|
175
|
+
addl $44, %esp
|
|
176
|
+
.cfi_def_cfa esp, 4
|
|
177
|
+
ret
|
|
178
|
+
.cfi_endproc
|
|
179
|
+
.endm
|
|
180
|
+
|
|
181
|
+
GetEIP:
|
|
182
|
+
movl (%esp), %ecx
|
|
183
|
+
ret
|
|
184
|
+
|
|
185
|
+
Trampoline0:
|
|
186
|
+
trampoline 0
|
|
187
|
+
Trampoline1:
|
|
188
|
+
trampoline 1
|
|
189
|
+
Trampoline2:
|
|
190
|
+
trampoline 2
|
|
191
|
+
Trampoline3:
|
|
192
|
+
trampoline 3
|
|
193
|
+
Trampoline4:
|
|
194
|
+
trampoline 4
|
|
195
|
+
Trampoline5:
|
|
196
|
+
trampoline 5
|
|
197
|
+
Trampoline6:
|
|
198
|
+
trampoline 6
|
|
199
|
+
Trampoline7:
|
|
200
|
+
trampoline 7
|
|
201
|
+
Trampoline8:
|
|
202
|
+
trampoline 8
|
|
203
|
+
Trampoline9:
|
|
204
|
+
trampoline 9
|
|
205
|
+
Trampoline10:
|
|
206
|
+
trampoline 10
|
|
207
|
+
Trampoline11:
|
|
208
|
+
trampoline 11
|
|
209
|
+
Trampoline12:
|
|
210
|
+
trampoline 12
|
|
211
|
+
Trampoline13:
|
|
212
|
+
trampoline 13
|
|
213
|
+
Trampoline14:
|
|
214
|
+
trampoline 14
|
|
215
|
+
Trampoline15:
|
|
216
|
+
trampoline 15
|
|
217
|
+
|
|
218
|
+
TrampolineX0:
|
|
219
|
+
trampoline_x87 0
|
|
220
|
+
TrampolineX1:
|
|
221
|
+
trampoline_x87 1
|
|
222
|
+
TrampolineX2:
|
|
223
|
+
trampoline_x87 2
|
|
224
|
+
TrampolineX3:
|
|
225
|
+
trampoline_x87 3
|
|
226
|
+
TrampolineX4:
|
|
227
|
+
trampoline_x87 4
|
|
228
|
+
TrampolineX5:
|
|
229
|
+
trampoline_x87 5
|
|
230
|
+
TrampolineX6:
|
|
231
|
+
trampoline_x87 6
|
|
232
|
+
TrampolineX7:
|
|
233
|
+
trampoline_x87 7
|
|
234
|
+
TrampolineX8:
|
|
235
|
+
trampoline_x87 8
|
|
236
|
+
TrampolineX9:
|
|
237
|
+
trampoline_x87 9
|
|
238
|
+
TrampolineX10:
|
|
239
|
+
trampoline_x87 10
|
|
240
|
+
TrampolineX11:
|
|
241
|
+
trampoline_x87 11
|
|
242
|
+
TrampolineX12:
|
|
243
|
+
trampoline_x87 12
|
|
244
|
+
TrampolineX13:
|
|
245
|
+
trampoline_x87 13
|
|
246
|
+
TrampolineX14:
|
|
247
|
+
trampoline_x87 14
|
|
248
|
+
TrampolineX15:
|
|
249
|
+
trampoline_x87 15
|
|
250
|
+
|
|
251
|
+
# When a callback is relayed, Koffi will call into Node.js and V8 to execute Javascript.
|
|
252
|
+
# The propblem is that we're still running on the separate Koffi stack, and V8 will
|
|
253
|
+
# preobably misdetect this as a "stack overflow". We have to restore the old
|
|
254
|
+
# stack pointer, call Node.js/V8 and go back to ours.
|
|
255
|
+
CallSwitchStack:
|
|
256
|
+
.cfi_startproc
|
|
257
|
+
.cfi_def_cfa esp, 4
|
|
258
|
+
endbr32
|
|
259
|
+
push %ebx
|
|
260
|
+
.cfi_def_cfa esp, 8
|
|
261
|
+
movl %esp, %ebx
|
|
262
|
+
.cfi_def_cfa ebx, 8
|
|
263
|
+
movl 28(%esp), %edx
|
|
264
|
+
movl 24(%esp), %ecx
|
|
265
|
+
movl %esp, %eax
|
|
266
|
+
subl 0(%ecx), %eax
|
|
267
|
+
andl $-16, %eax
|
|
268
|
+
movl %eax, 4(%ecx)
|
|
269
|
+
movl 20(%esp), %esp
|
|
270
|
+
subl $16, %esp
|
|
271
|
+
movl 8(%ebx), %eax
|
|
272
|
+
movl %eax, 0(%esp)
|
|
273
|
+
movl 12(%ebx), %eax
|
|
274
|
+
movl %eax, 4(%esp)
|
|
275
|
+
movl 16(%ebx), %eax
|
|
276
|
+
movl %eax, 8(%esp)
|
|
277
|
+
call *%edx
|
|
278
|
+
mov %ebx, %esp
|
|
279
|
+
.cfi_def_cfa esp, 8
|
|
280
|
+
pop %ebx
|
|
281
|
+
.cfi_def_cfa esp, 4
|
|
282
|
+
ret
|
|
283
|
+
.cfi_endproc
|
package/src/abi_x86_fwd.asm
CHANGED
|
@@ -11,6 +11,9 @@
|
|
|
11
11
|
; You should have received a copy of the GNU Affero General Public License
|
|
12
12
|
; along with this program. If not, see https://www.gnu.org/licenses/.
|
|
13
13
|
|
|
14
|
+
; Forward
|
|
15
|
+
; ----------------------------
|
|
16
|
+
|
|
14
17
|
public ForwardCallG
|
|
15
18
|
public ForwardCallF
|
|
16
19
|
public ForwardCallD
|
|
@@ -22,11 +25,14 @@ public ForwardCallRD
|
|
|
22
25
|
.code
|
|
23
26
|
|
|
24
27
|
; Copy function pointer to EAX, in order to save it through argument forwarding.
|
|
28
|
+
; Also make a copy of the SP to CallData::old_sp because the callback system might need it.
|
|
25
29
|
; Save ESP in EBX (non-volatile), and use carefully assembled stack provided by caller.
|
|
26
30
|
prologue macro
|
|
27
31
|
endbr32
|
|
28
32
|
push ebx
|
|
29
33
|
mov ebx, esp
|
|
34
|
+
mov eax, dword ptr [esp+16]
|
|
35
|
+
mov dword ptr [eax+0], esp
|
|
30
36
|
mov eax, dword ptr [esp+8]
|
|
31
37
|
mov esp, dword ptr [esp+12]
|
|
32
38
|
endm
|
|
@@ -80,4 +86,216 @@ ForwardCallRD proc
|
|
|
80
86
|
epilogue
|
|
81
87
|
ForwardCallRD endp
|
|
82
88
|
|
|
89
|
+
; Callback trampolines
|
|
90
|
+
; ----------------------------
|
|
91
|
+
|
|
92
|
+
public Trampoline0
|
|
93
|
+
public Trampoline1
|
|
94
|
+
public Trampoline2
|
|
95
|
+
public Trampoline3
|
|
96
|
+
public Trampoline4
|
|
97
|
+
public Trampoline5
|
|
98
|
+
public Trampoline6
|
|
99
|
+
public Trampoline7
|
|
100
|
+
public Trampoline8
|
|
101
|
+
public Trampoline9
|
|
102
|
+
public Trampoline10
|
|
103
|
+
public Trampoline11
|
|
104
|
+
public Trampoline12
|
|
105
|
+
public Trampoline13
|
|
106
|
+
public Trampoline14
|
|
107
|
+
public Trampoline15
|
|
108
|
+
public TrampolineX0
|
|
109
|
+
public TrampolineX1
|
|
110
|
+
public TrampolineX2
|
|
111
|
+
public TrampolineX3
|
|
112
|
+
public TrampolineX4
|
|
113
|
+
public TrampolineX5
|
|
114
|
+
public TrampolineX6
|
|
115
|
+
public TrampolineX7
|
|
116
|
+
public TrampolineX8
|
|
117
|
+
public TrampolineX9
|
|
118
|
+
public TrampolineX10
|
|
119
|
+
public TrampolineX11
|
|
120
|
+
public TrampolineX12
|
|
121
|
+
public TrampolineX13
|
|
122
|
+
public TrampolineX14
|
|
123
|
+
public TrampolineX15
|
|
124
|
+
extern RelayCallBack : PROC
|
|
125
|
+
public CallSwitchStack
|
|
126
|
+
|
|
127
|
+
; Call the C function RelayCallBack with the following arguments:
|
|
128
|
+
; static trampoline ID, the current stack pointer, a pointer to the stack arguments of this call,
|
|
129
|
+
; and a pointer to a struct that will contain the result registers.
|
|
130
|
+
; After the call, simply load these registers from the output struct.
|
|
131
|
+
trampoline macro ID
|
|
132
|
+
endbr32
|
|
133
|
+
sub esp, 44
|
|
134
|
+
mov dword ptr [esp+0], ID
|
|
135
|
+
mov dword ptr [esp+4], esp
|
|
136
|
+
lea eax, dword ptr [esp+48]
|
|
137
|
+
mov dword ptr [esp+8], eax
|
|
138
|
+
lea eax, dword ptr [esp+16]
|
|
139
|
+
mov dword ptr [esp+12], eax
|
|
140
|
+
call RelayCallBack
|
|
141
|
+
mov eax, dword ptr[esp+16]
|
|
142
|
+
mov edx, dword ptr[esp+20]
|
|
143
|
+
add esp, 44
|
|
144
|
+
ret
|
|
145
|
+
endm
|
|
146
|
+
|
|
147
|
+
; This version also loads the x87 stack with the result, if need be.
|
|
148
|
+
; We have to branch to avoid x87 stack imbalance.
|
|
149
|
+
trampoline_x87 macro ID
|
|
150
|
+
local l1, l2, l3
|
|
151
|
+
|
|
152
|
+
endbr32
|
|
153
|
+
sub esp, 44
|
|
154
|
+
mov dword ptr [esp+0], ID
|
|
155
|
+
mov dword ptr [esp+4], esp
|
|
156
|
+
lea eax, dword ptr [esp+48]
|
|
157
|
+
mov dword ptr [esp+8], eax
|
|
158
|
+
lea eax, dword ptr [esp+16]
|
|
159
|
+
mov dword ptr [esp+12], eax
|
|
160
|
+
call RelayCallBack
|
|
161
|
+
cmp byte ptr[esp+36], 1
|
|
162
|
+
je l2
|
|
163
|
+
l1:
|
|
164
|
+
fld dword ptr [esp+32]
|
|
165
|
+
jmp l3
|
|
166
|
+
l2:
|
|
167
|
+
fld qword ptr [esp+24]
|
|
168
|
+
l3:
|
|
169
|
+
mov eax, dword ptr[esp+16]
|
|
170
|
+
mov edx, dword ptr[esp+20]
|
|
171
|
+
add esp, 44
|
|
172
|
+
ret
|
|
173
|
+
endm
|
|
174
|
+
|
|
175
|
+
Trampoline0 proc
|
|
176
|
+
trampoline 0
|
|
177
|
+
Trampoline0 endp
|
|
178
|
+
Trampoline1 proc
|
|
179
|
+
trampoline 1
|
|
180
|
+
Trampoline1 endp
|
|
181
|
+
Trampoline2 proc
|
|
182
|
+
trampoline 2
|
|
183
|
+
Trampoline2 endp
|
|
184
|
+
Trampoline3 proc
|
|
185
|
+
trampoline 3
|
|
186
|
+
Trampoline3 endp
|
|
187
|
+
Trampoline4 proc
|
|
188
|
+
trampoline 4
|
|
189
|
+
Trampoline4 endp
|
|
190
|
+
Trampoline5 proc
|
|
191
|
+
trampoline 5
|
|
192
|
+
Trampoline5 endp
|
|
193
|
+
Trampoline6 proc
|
|
194
|
+
trampoline 6
|
|
195
|
+
Trampoline6 endp
|
|
196
|
+
Trampoline7 proc
|
|
197
|
+
trampoline 7
|
|
198
|
+
Trampoline7 endp
|
|
199
|
+
Trampoline8 proc
|
|
200
|
+
trampoline 8
|
|
201
|
+
Trampoline8 endp
|
|
202
|
+
Trampoline9 proc
|
|
203
|
+
trampoline 9
|
|
204
|
+
Trampoline9 endp
|
|
205
|
+
Trampoline10 proc
|
|
206
|
+
trampoline 10
|
|
207
|
+
Trampoline10 endp
|
|
208
|
+
Trampoline11 proc
|
|
209
|
+
trampoline 11
|
|
210
|
+
Trampoline11 endp
|
|
211
|
+
Trampoline12 proc
|
|
212
|
+
trampoline 12
|
|
213
|
+
Trampoline12 endp
|
|
214
|
+
Trampoline13 proc
|
|
215
|
+
trampoline 13
|
|
216
|
+
Trampoline13 endp
|
|
217
|
+
Trampoline14 proc
|
|
218
|
+
trampoline 14
|
|
219
|
+
Trampoline14 endp
|
|
220
|
+
Trampoline15 proc
|
|
221
|
+
trampoline 15
|
|
222
|
+
Trampoline15 endp
|
|
223
|
+
|
|
224
|
+
TrampolineX0 proc
|
|
225
|
+
trampoline_x87 0
|
|
226
|
+
TrampolineX0 endp
|
|
227
|
+
TrampolineX1 proc
|
|
228
|
+
trampoline_x87 1
|
|
229
|
+
TrampolineX1 endp
|
|
230
|
+
TrampolineX2 proc
|
|
231
|
+
trampoline_x87 2
|
|
232
|
+
TrampolineX2 endp
|
|
233
|
+
TrampolineX3 proc
|
|
234
|
+
trampoline_x87 3
|
|
235
|
+
TrampolineX3 endp
|
|
236
|
+
TrampolineX4 proc
|
|
237
|
+
trampoline_x87 4
|
|
238
|
+
TrampolineX4 endp
|
|
239
|
+
TrampolineX5 proc
|
|
240
|
+
trampoline_x87 5
|
|
241
|
+
TrampolineX5 endp
|
|
242
|
+
TrampolineX6 proc
|
|
243
|
+
trampoline_x87 6
|
|
244
|
+
TrampolineX6 endp
|
|
245
|
+
TrampolineX7 proc
|
|
246
|
+
trampoline_x87 7
|
|
247
|
+
TrampolineX7 endp
|
|
248
|
+
TrampolineX8 proc
|
|
249
|
+
trampoline_x87 8
|
|
250
|
+
TrampolineX8 endp
|
|
251
|
+
TrampolineX9 proc
|
|
252
|
+
trampoline_x87 9
|
|
253
|
+
TrampolineX9 endp
|
|
254
|
+
TrampolineX10 proc
|
|
255
|
+
trampoline_x87 10
|
|
256
|
+
TrampolineX10 endp
|
|
257
|
+
TrampolineX11 proc
|
|
258
|
+
trampoline_x87 11
|
|
259
|
+
TrampolineX11 endp
|
|
260
|
+
TrampolineX12 proc
|
|
261
|
+
trampoline_x87 12
|
|
262
|
+
TrampolineX12 endp
|
|
263
|
+
TrampolineX13 proc
|
|
264
|
+
trampoline_x87 13
|
|
265
|
+
TrampolineX13 endp
|
|
266
|
+
TrampolineX14 proc
|
|
267
|
+
trampoline_x87 14
|
|
268
|
+
TrampolineX14 endp
|
|
269
|
+
TrampolineX15 proc
|
|
270
|
+
trampoline_x87 15
|
|
271
|
+
TrampolineX15 endp
|
|
272
|
+
|
|
273
|
+
; When a callback is relayed, Koffi will call into Node.js and V8 to execute Javascript.
|
|
274
|
+
; The propblem is that we're still running on the separate Koffi stack, and V8 will
|
|
275
|
+
; preobably misdetect this as a "stack overflow". We have to restore the old
|
|
276
|
+
; stack pointer, call Node.js/V8 and go back to ours.
|
|
277
|
+
CallSwitchStack proc
|
|
278
|
+
endbr32
|
|
279
|
+
push ebx
|
|
280
|
+
mov ebx, esp
|
|
281
|
+
mov edx, dword ptr [esp+28]
|
|
282
|
+
mov ecx, dword ptr [esp+24]
|
|
283
|
+
mov eax, esp
|
|
284
|
+
sub eax, dword ptr [ecx+0]
|
|
285
|
+
and eax, -16
|
|
286
|
+
mov dword ptr [ecx+4], eax
|
|
287
|
+
mov esp, dword ptr [esp+20]
|
|
288
|
+
sub esp, 28
|
|
289
|
+
mov eax, dword ptr [ebx+8]
|
|
290
|
+
mov dword ptr [esp+0], eax
|
|
291
|
+
mov eax, dword ptr [ebx+12]
|
|
292
|
+
mov dword ptr [esp+4], eax
|
|
293
|
+
mov eax, dword ptr [ebx+16]
|
|
294
|
+
mov dword ptr [esp+8], eax
|
|
295
|
+
call edx
|
|
296
|
+
mov esp, ebx
|
|
297
|
+
pop ebx
|
|
298
|
+
ret
|
|
299
|
+
CallSwitchStack endp
|
|
300
|
+
|
|
83
301
|
end
|
package/src/call.cc
CHANGED
|
@@ -35,7 +35,9 @@ CallData::~CallData()
|
|
|
35
35
|
mem->stack = old_stack_mem;
|
|
36
36
|
mem->heap = old_heap_mem;
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
instance->free_trampolines |= used_trampolines;
|
|
39
|
+
|
|
40
|
+
if (--mem->depth && mem->temporary) {
|
|
39
41
|
delete mem;
|
|
40
42
|
}
|
|
41
43
|
}
|
|
@@ -237,14 +239,16 @@ bool CallData::PushObject(const Napi::Object &obj, const TypeInfo *type, uint8_t
|
|
|
237
239
|
*(const char16_t **)dest = str16;
|
|
238
240
|
} break;
|
|
239
241
|
case PrimitiveKind::Pointer: {
|
|
240
|
-
if (
|
|
242
|
+
if (CheckValueTag(instance, value, member.type)) {
|
|
243
|
+
Napi::External external = value.As<Napi::External<void>>();
|
|
244
|
+
void *ptr = external.Data();
|
|
245
|
+
*(void **)dest = ptr;
|
|
246
|
+
} else if (IsNullOrUndefined(value)) {
|
|
247
|
+
*(void **)dest = nullptr;
|
|
248
|
+
} else {
|
|
241
249
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for member '%2', expected %3", GetValueType(instance, value), member.name, member.type->name);
|
|
242
250
|
return false;
|
|
243
251
|
}
|
|
244
|
-
|
|
245
|
-
Napi::External external = value.As<Napi::External<void>>();
|
|
246
|
-
void *ptr = external.Data();
|
|
247
|
-
*(void **)dest = ptr;
|
|
248
252
|
} break;
|
|
249
253
|
case PrimitiveKind::Record: {
|
|
250
254
|
if (RG_UNLIKELY(!IsObject(value))) {
|
|
@@ -284,6 +288,29 @@ bool CallData::PushObject(const Napi::Object &obj, const TypeInfo *type, uint8_t
|
|
|
284
288
|
double d = CopyNumber<double>(value);
|
|
285
289
|
*(double *)dest = d;
|
|
286
290
|
} break;
|
|
291
|
+
case PrimitiveKind::Callback: {
|
|
292
|
+
void *ptr;
|
|
293
|
+
|
|
294
|
+
if (value.IsFunction()) {
|
|
295
|
+
Napi::Function func = value.As<Napi::Function>();
|
|
296
|
+
|
|
297
|
+
Size idx = ReserveTrampoline(member.type->proto, func);
|
|
298
|
+
if (RG_UNLIKELY(idx < 0))
|
|
299
|
+
return false;
|
|
300
|
+
|
|
301
|
+
ptr = GetTrampoline(idx, member.type->proto);
|
|
302
|
+
} else if (CheckValueTag(instance, value, member.type)) {
|
|
303
|
+
Napi::External external = value.As<Napi::External<void>>();
|
|
304
|
+
ptr = external.Data();
|
|
305
|
+
} else if (IsNullOrUndefined(value)) {
|
|
306
|
+
ptr = nullptr;
|
|
307
|
+
} else {
|
|
308
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for member '%2', expected %3", GetValueType(instance, value), member.name, member.type->name);
|
|
309
|
+
return false;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
*(void **)dest = ptr;
|
|
313
|
+
} break;
|
|
287
314
|
}
|
|
288
315
|
|
|
289
316
|
dest += member.type->size;
|
|
@@ -400,9 +427,13 @@ bool CallData::PushArray(const Napi::Value &obj, const TypeInfo *type, uint8_t *
|
|
|
400
427
|
});
|
|
401
428
|
} break;
|
|
402
429
|
case PrimitiveKind::Pointer: {
|
|
403
|
-
PUSH_ARRAY(CheckValueTag(instance, value, type->ref), type->ref->name, {
|
|
404
|
-
|
|
405
|
-
|
|
430
|
+
PUSH_ARRAY(CheckValueTag(instance, value, type->ref) || IsNullOrUndefined(value), type->ref->name, {
|
|
431
|
+
if (!IsNullOrUndefined(value)) {
|
|
432
|
+
Napi::External external = value.As<Napi::External<void>>();
|
|
433
|
+
*(void **)dest = external.Data();
|
|
434
|
+
} else {
|
|
435
|
+
*(void **)dest = nullptr;
|
|
436
|
+
}
|
|
406
437
|
});
|
|
407
438
|
} break;
|
|
408
439
|
case PrimitiveKind::Record: {
|
|
@@ -431,6 +462,38 @@ bool CallData::PushArray(const Napi::Value &obj, const TypeInfo *type, uint8_t *
|
|
|
431
462
|
*(double *)dest = d;
|
|
432
463
|
});
|
|
433
464
|
} break;
|
|
465
|
+
case PrimitiveKind::Callback: {
|
|
466
|
+
for (uint32_t i = 0; i < len; i++) {
|
|
467
|
+
Napi::Value value = array[i];
|
|
468
|
+
|
|
469
|
+
int16_t align = std::max(type->ref->align, realign);
|
|
470
|
+
dest = AlignUp(dest, align);
|
|
471
|
+
|
|
472
|
+
void *ptr;
|
|
473
|
+
|
|
474
|
+
if (value.IsFunction()) {
|
|
475
|
+
Napi::Function func = value.As<Napi::Function>();
|
|
476
|
+
|
|
477
|
+
Size idx = ReserveTrampoline(type->ref->proto, func);
|
|
478
|
+
if (RG_UNLIKELY(idx < 0))
|
|
479
|
+
return false;
|
|
480
|
+
|
|
481
|
+
ptr = GetTrampoline(idx, type->ref->proto);
|
|
482
|
+
} else if (CheckValueTag(instance, value, type->ref)) {
|
|
483
|
+
Napi::External external = value.As<Napi::External<void>>();
|
|
484
|
+
ptr = external.Data();
|
|
485
|
+
} else if (IsNullOrUndefined(value)) {
|
|
486
|
+
ptr = nullptr;
|
|
487
|
+
} else {
|
|
488
|
+
ThrowError<Napi::TypeError>(env, "Unexpected value %1 in array, expected %2", GetValueType(instance, value), type->ref->name);
|
|
489
|
+
return false;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
*(void **)dest = ptr;
|
|
493
|
+
|
|
494
|
+
dest += type->ref->size;
|
|
495
|
+
}
|
|
496
|
+
} break;
|
|
434
497
|
}
|
|
435
498
|
|
|
436
499
|
#undef PUSH_ARRAY
|
|
@@ -493,8 +556,29 @@ bool CallData::PushArray(const Napi::Value &obj, const TypeInfo *type, uint8_t *
|
|
|
493
556
|
return true;
|
|
494
557
|
}
|
|
495
558
|
|
|
559
|
+
Size CallData::ReserveTrampoline(const FunctionInfo *proto, Napi::Function func)
|
|
560
|
+
{
|
|
561
|
+
uint32_t idx = CountTrailingZeros(instance->free_trampolines);
|
|
562
|
+
|
|
563
|
+
if (RG_UNLIKELY(idx >= MaxTrampolines)) {
|
|
564
|
+
ThrowError<Napi::Error>(env, "Too many callbacks are in use (max = %1)", MaxTrampolines);
|
|
565
|
+
return -1;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
instance->free_trampolines &= ~(1u << idx);
|
|
569
|
+
used_trampolines |= 1u << idx;
|
|
570
|
+
|
|
571
|
+
instance->trampolines[idx].proto = proto;
|
|
572
|
+
instance->trampolines[idx].func = func;
|
|
573
|
+
|
|
574
|
+
return idx;
|
|
575
|
+
}
|
|
576
|
+
|
|
496
577
|
void CallData::PopObject(Napi::Object obj, const uint8_t *src, const TypeInfo *type, int16_t realign)
|
|
497
578
|
{
|
|
579
|
+
Napi::Env env = obj.Env();
|
|
580
|
+
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
581
|
+
|
|
498
582
|
RG_ASSERT(type->primitive == PrimitiveKind::Record);
|
|
499
583
|
|
|
500
584
|
for (const RecordMember &member: type->members) {
|
|
@@ -548,13 +632,18 @@ void CallData::PopObject(Napi::Object obj, const uint8_t *src, const TypeInfo *t
|
|
|
548
632
|
const char16_t *str16 = *(const char16_t **)src;
|
|
549
633
|
obj.Set(member.name, Napi::String::New(env, str16));
|
|
550
634
|
} break;
|
|
551
|
-
case PrimitiveKind::Pointer:
|
|
635
|
+
case PrimitiveKind::Pointer:
|
|
636
|
+
case PrimitiveKind::Callback: {
|
|
552
637
|
void *ptr2 = *(void **)src;
|
|
553
638
|
|
|
554
|
-
|
|
555
|
-
|
|
639
|
+
if (ptr2) {
|
|
640
|
+
Napi::External<void> external = Napi::External<void>::New(env, ptr2);
|
|
641
|
+
SetValueTag(instance, external, member.type);
|
|
556
642
|
|
|
557
|
-
|
|
643
|
+
obj.Set(member.name, external);
|
|
644
|
+
} else {
|
|
645
|
+
obj.Set(member.name, env.Null());
|
|
646
|
+
}
|
|
558
647
|
} break;
|
|
559
648
|
case PrimitiveKind::Record: {
|
|
560
649
|
Napi::Object obj2 = PopObject(src, member.type, realign);
|
|
@@ -598,6 +687,8 @@ Size WideStringLength(const char16_t *str16, Size max)
|
|
|
598
687
|
|
|
599
688
|
Napi::Value CallData::PopArray(const uint8_t *src, const TypeInfo *type, int16_t realign)
|
|
600
689
|
{
|
|
690
|
+
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
691
|
+
|
|
601
692
|
RG_ASSERT(type->primitive == PrimitiveKind::Array);
|
|
602
693
|
|
|
603
694
|
uint32_t len = type->size / type->ref->size;
|
|
@@ -728,14 +819,19 @@ Napi::Value CallData::PopArray(const uint8_t *src, const TypeInfo *type, int16_t
|
|
|
728
819
|
array.Set(i, Napi::String::New(env, str16));
|
|
729
820
|
});
|
|
730
821
|
} break;
|
|
731
|
-
case PrimitiveKind::Pointer:
|
|
822
|
+
case PrimitiveKind::Pointer:
|
|
823
|
+
case PrimitiveKind::Callback: {
|
|
732
824
|
POP_ARRAY({
|
|
733
825
|
void *ptr2 = *(void **)src;
|
|
734
826
|
|
|
735
|
-
|
|
736
|
-
|
|
827
|
+
if (ptr2) {
|
|
828
|
+
Napi::External<void> external = Napi::External<void>::New(env, ptr2);
|
|
829
|
+
SetValueTag(instance, external, type->ref);
|
|
737
830
|
|
|
738
|
-
|
|
831
|
+
array.Set(i, external);
|
|
832
|
+
} else {
|
|
833
|
+
array.Set(i, env.Null());
|
|
834
|
+
}
|
|
739
835
|
});
|
|
740
836
|
} break;
|
|
741
837
|
case PrimitiveKind::Record: {
|