diff options
Diffstat (limited to '')
-rw-r--r-- | libraries/luajit-2.0/src/lj_ccall.c | 675 |
1 files changed, 0 insertions, 675 deletions
diff --git a/libraries/luajit-2.0/src/lj_ccall.c b/libraries/luajit-2.0/src/lj_ccall.c deleted file mode 100644 index 5ed1bf5..0000000 --- a/libraries/luajit-2.0/src/lj_ccall.c +++ /dev/null | |||
@@ -1,675 +0,0 @@ | |||
1 | /* | ||
2 | ** FFI C call handling. | ||
3 | ** Copyright (C) 2005-2011 Mike Pall. See Copyright Notice in luajit.h | ||
4 | */ | ||
5 | |||
6 | #include "lj_obj.h" | ||
7 | |||
8 | #if LJ_HASFFI | ||
9 | |||
10 | #include "lj_gc.h" | ||
11 | #include "lj_err.h" | ||
12 | #include "lj_str.h" | ||
13 | #include "lj_tab.h" | ||
14 | #include "lj_ctype.h" | ||
15 | #include "lj_cconv.h" | ||
16 | #include "lj_cdata.h" | ||
17 | #include "lj_ccall.h" | ||
18 | #include "lj_trace.h" | ||
19 | |||
20 | /* Target-specific handling of register arguments. */ | ||
21 | #if LJ_TARGET_X86 | ||
22 | /* -- x86 calling conventions --------------------------------------------- */ | ||
23 | |||
24 | #if LJ_ABI_WIN | ||
25 | |||
26 | #define CCALL_HANDLE_STRUCTRET \ | ||
27 | /* Return structs bigger than 8 by reference (on stack only). */ \ | ||
28 | cc->retref = (sz > 8); \ | ||
29 | if (cc->retref) cc->stack[nsp++] = (GPRArg)dp; | ||
30 | |||
31 | #define CCALL_HANDLE_COMPLEXRET CCALL_HANDLE_STRUCTRET | ||
32 | |||
33 | #else | ||
34 | |||
35 | #define CCALL_HANDLE_STRUCTRET \ | ||
36 | cc->retref = 1; /* Return all structs by reference (in reg or on stack). */ \ | ||
37 | if (ngpr < maxgpr) \ | ||
38 | cc->gpr[ngpr++] = (GPRArg)dp; \ | ||
39 | else \ | ||
40 | cc->stack[nsp++] = (GPRArg)dp; | ||
41 | |||
42 | #define CCALL_HANDLE_COMPLEXRET \ | ||
43 | /* Return complex float in GPRs and complex double by reference. */ \ | ||
44 | cc->retref = (sz > 8); \ | ||
45 | if (cc->retref) { \ | ||
46 | if (ngpr < maxgpr) \ | ||
47 | cc->gpr[ngpr++] = (GPRArg)dp; \ | ||
48 | else \ | ||
49 | cc->stack[nsp++] = (GPRArg)dp; \ | ||
50 | } | ||
51 | |||
52 | #endif | ||
53 | |||
54 | #define CCALL_HANDLE_COMPLEXRET2 \ | ||
55 | if (!cc->retref) \ | ||
56 | *(int64_t *)dp = *(int64_t *)sp; /* Copy complex float from GPRs. */ | ||
57 | |||
58 | #define CCALL_HANDLE_STRUCTARG \ | ||
59 | ngpr = maxgpr; /* Pass all structs by value on the stack. */ | ||
60 | |||
61 | #define CCALL_HANDLE_COMPLEXARG \ | ||
62 | isfp = 1; /* Pass complex by value on stack. */ | ||
63 | |||
64 | #define CCALL_HANDLE_REGARG \ | ||
65 | if (!isfp) { /* Only non-FP values may be passed in registers. */ \ | ||
66 | if (n > 1) { /* Anything > 32 bit is passed on the stack. */ \ | ||
67 | if (!LJ_ABI_WIN) ngpr = maxgpr; /* Prevent reordering. */ \ | ||
68 | } else if (ngpr + 1 <= maxgpr) { \ | ||
69 | dp = &cc->gpr[ngpr]; \ | ||
70 | ngpr += n; \ | ||
71 | goto done; \ | ||
72 | } \ | ||
73 | } | ||
74 | |||
75 | #elif LJ_TARGET_X64 && LJ_ABI_WIN | ||
76 | /* -- Windows/x64 calling conventions ------------------------------------- */ | ||
77 | |||
78 | #define CCALL_HANDLE_STRUCTRET \ | ||
79 | /* Return structs of size 1, 2, 4 or 8 in a GPR. */ \ | ||
80 | cc->retref = !(sz == 1 || sz == 2 || sz == 4 || sz == 8); \ | ||
81 | if (cc->retref) cc->gpr[ngpr++] = (GPRArg)dp; | ||
82 | |||
83 | #define CCALL_HANDLE_COMPLEXRET CCALL_HANDLE_STRUCTRET | ||
84 | |||
85 | #define CCALL_HANDLE_COMPLEXRET2 \ | ||
86 | if (!cc->retref) \ | ||
87 | *(int64_t *)dp = *(int64_t *)sp; /* Copy complex float from GPRs. */ | ||
88 | |||
89 | #define CCALL_HANDLE_STRUCTARG \ | ||
90 | /* Pass structs of size 1, 2, 4 or 8 in a GPR by value. */ \ | ||
91 | if (!(sz == 1 || sz == 2 || sz == 4 || sz == 8)) { \ | ||
92 | rp = cdataptr(lj_cdata_new(cts, did, sz)); \ | ||
93 | sz = CTSIZE_PTR; /* Pass all other structs by reference. */ \ | ||
94 | } | ||
95 | |||
96 | #define CCALL_HANDLE_COMPLEXARG \ | ||
97 | /* Pass complex float in a GPR and complex double by reference. */ \ | ||
98 | if (sz != 2*sizeof(float)) { \ | ||
99 | rp = cdataptr(lj_cdata_new(cts, did, sz)); \ | ||
100 | sz = CTSIZE_PTR; \ | ||
101 | } | ||
102 | |||
103 | /* Windows/x64 argument registers are strictly positional (use ngpr). */ | ||
104 | #define CCALL_HANDLE_REGARG \ | ||
105 | if (isfp) { \ | ||
106 | if (ngpr < 4) { dp = &cc->fpr[ngpr++]; nfpr = ngpr; goto done; } \ | ||
107 | } else { \ | ||
108 | if (ngpr < 4) { dp = &cc->gpr[ngpr++]; goto done; } \ | ||
109 | } | ||
110 | |||
111 | #elif LJ_TARGET_X64 | ||
112 | /* -- POSIX/x64 calling conventions --------------------------------------- */ | ||
113 | |||
114 | #define CCALL_HANDLE_STRUCTRET \ | ||
115 | int rcl[2]; rcl[0] = rcl[1] = 0; \ | ||
116 | if (ccall_classify_struct(cts, ctr, rcl, 0)) { \ | ||
117 | cc->retref = 1; /* Return struct by reference. */ \ | ||
118 | cc->gpr[ngpr++] = (GPRArg)dp; \ | ||
119 | } else { \ | ||
120 | cc->retref = 0; /* Return small structs in registers. */ \ | ||
121 | } | ||
122 | |||
123 | #define CCALL_HANDLE_STRUCTRET2 \ | ||
124 | int rcl[2]; rcl[0] = rcl[1] = 0; \ | ||
125 | ccall_classify_struct(cts, ctr, rcl, 0); \ | ||
126 | ccall_struct_ret(cc, rcl, dp, ctr->size); | ||
127 | |||
128 | #define CCALL_HANDLE_COMPLEXRET \ | ||
129 | /* Complex values are returned in one or two FPRs. */ \ | ||
130 | cc->retref = 0; | ||
131 | |||
132 | #define CCALL_HANDLE_COMPLEXRET2 \ | ||
133 | if (ctr->size == 2*sizeof(float)) { /* Copy complex float from FPR. */ \ | ||
134 | *(int64_t *)dp = cc->fpr[0].l[0]; \ | ||
135 | } else { /* Copy non-contiguous complex double from FPRs. */ \ | ||
136 | ((int64_t *)dp)[0] = cc->fpr[0].l[0]; \ | ||
137 | ((int64_t *)dp)[1] = cc->fpr[1].l[0]; \ | ||
138 | } | ||
139 | |||
140 | #define CCALL_HANDLE_STRUCTARG \ | ||
141 | int rcl[2]; rcl[0] = rcl[1] = 0; \ | ||
142 | if (!ccall_classify_struct(cts, d, rcl, 0)) { \ | ||
143 | cc->nsp = nsp; cc->ngpr = ngpr; cc->nfpr = nfpr; \ | ||
144 | if (ccall_struct_arg(cc, cts, d, rcl, o, narg)) goto err_nyi; \ | ||
145 | nsp = cc->nsp; ngpr = cc->ngpr; nfpr = cc->nfpr; \ | ||
146 | continue; \ | ||
147 | } /* Pass all other structs by value on stack. */ | ||
148 | |||
149 | #define CCALL_HANDLE_COMPLEXARG \ | ||
150 | isfp = 2; /* Pass complex in FPRs or on stack. Needs postprocessing. */ | ||
151 | |||
152 | #define CCALL_HANDLE_REGARG \ | ||
153 | if (isfp) { /* Try to pass argument in FPRs. */ \ | ||
154 | if (nfpr + n <= CCALL_NARG_FPR) { \ | ||
155 | dp = &cc->fpr[nfpr]; \ | ||
156 | nfpr += n; \ | ||
157 | goto done; \ | ||
158 | } \ | ||
159 | } else { /* Try to pass argument in GPRs. */ \ | ||
160 | /* Note that reordering is explicitly allowed in the x64 ABI. */ \ | ||
161 | if (n <= 2 && ngpr + n <= maxgpr) { \ | ||
162 | dp = &cc->gpr[ngpr]; \ | ||
163 | ngpr += n; \ | ||
164 | goto done; \ | ||
165 | } \ | ||
166 | } | ||
167 | |||
168 | #elif LJ_TARGET_ARM | ||
169 | /* -- ARM calling conventions --------------------------------------------- */ | ||
170 | |||
171 | #define CCALL_HANDLE_STRUCTRET \ | ||
172 | /* Return structs of size <= 4 in a GPR. */ \ | ||
173 | cc->retref = !(sz <= 4); \ | ||
174 | if (cc->retref) cc->gpr[ngpr++] = (GPRArg)dp; | ||
175 | |||
176 | #define CCALL_HANDLE_COMPLEXRET \ | ||
177 | cc->retref = 1; /* Return all complex values by reference. */ \ | ||
178 | cc->gpr[ngpr++] = (GPRArg)dp; | ||
179 | |||
180 | #define CCALL_HANDLE_COMPLEXRET2 \ | ||
181 | UNUSED(dp); /* Nothing to do. */ | ||
182 | |||
183 | #define CCALL_HANDLE_STRUCTARG \ | ||
184 | /* Pass all structs by value in registers and/or on the stack. */ | ||
185 | |||
186 | #define CCALL_HANDLE_COMPLEXARG \ | ||
187 | /* Pass complex by value in 2 or 4 GPRs. */ | ||
188 | |||
189 | /* ARM has a softfp ABI. */ | ||
190 | #define CCALL_HANDLE_REGARG \ | ||
191 | if ((d->info & CTF_ALIGN) > CTALIGN_PTR) { \ | ||
192 | if (ngpr < maxgpr) \ | ||
193 | ngpr = (ngpr + 1u) & ~1u; /* Align to regpair. */ \ | ||
194 | else \ | ||
195 | nsp = (nsp + 1u) & ~1u; /* Align argument on stack. */ \ | ||
196 | } \ | ||
197 | if (ngpr < maxgpr) { \ | ||
198 | dp = &cc->gpr[ngpr]; \ | ||
199 | if (ngpr + n > maxgpr) { \ | ||
200 | nsp += ngpr + n - maxgpr; /* Assumes contiguous gpr/stack fields. */ \ | ||
201 | if (nsp > CCALL_MAXSTACK) goto err_nyi; /* Too many arguments. */ \ | ||
202 | ngpr = maxgpr; \ | ||
203 | } else { \ | ||
204 | ngpr += n; \ | ||
205 | } \ | ||
206 | goto done; \ | ||
207 | } | ||
208 | |||
209 | #elif LJ_TARGET_PPC | ||
210 | /* -- PPC calling conventions --------------------------------------------- */ | ||
211 | |||
212 | #define CCALL_HANDLE_STRUCTRET \ | ||
213 | cc->retref = 1; /* Return all structs by reference. */ \ | ||
214 | cc->gpr[ngpr++] = (GPRArg)dp; | ||
215 | |||
216 | #define CCALL_HANDLE_COMPLEXRET \ | ||
217 | /* Complex values are returned in 2 or 4 GPRs. */ \ | ||
218 | cc->retref = 0; | ||
219 | |||
220 | #define CCALL_HANDLE_COMPLEXRET2 \ | ||
221 | memcpy(dp, sp, ctr->size); /* Copy complex from GPRs. */ | ||
222 | |||
223 | #define CCALL_HANDLE_STRUCTARG \ | ||
224 | rp = cdataptr(lj_cdata_new(cts, did, sz)); \ | ||
225 | sz = CTSIZE_PTR; /* Pass all structs by reference. */ | ||
226 | |||
227 | #define CCALL_HANDLE_COMPLEXARG \ | ||
228 | /* Pass complex by value in 2 or 4 GPRs. */ | ||
229 | |||
230 | #define CCALL_HANDLE_REGARG \ | ||
231 | if (isfp) { /* Try to pass argument in FPRs. */ \ | ||
232 | if (nfpr + 1 <= CCALL_NARG_FPR) { \ | ||
233 | dp = &cc->fpr[nfpr]; \ | ||
234 | nfpr += 1; \ | ||
235 | d = ctype_get(cts, CTID_DOUBLE); /* FPRs always hold doubles. */ \ | ||
236 | goto done; \ | ||
237 | } \ | ||
238 | } else { /* Try to pass argument in GPRs. */ \ | ||
239 | if (n > 1) { \ | ||
240 | lua_assert(n == 2 || n == 4); /* int64_t or complex (float). */ \ | ||
241 | if (ctype_isinteger(d->info)) \ | ||
242 | ngpr = (ngpr + 1u) & ~1u; /* Align int64_t to regpair. */ \ | ||
243 | else if (ngpr + n > maxgpr) \ | ||
244 | ngpr = maxgpr; /* Prevent reordering. */ \ | ||
245 | } \ | ||
246 | if (ngpr + n <= maxgpr) { \ | ||
247 | dp = &cc->gpr[ngpr]; \ | ||
248 | ngpr += n; \ | ||
249 | goto done; \ | ||
250 | } \ | ||
251 | } | ||
252 | |||
253 | #define CCALL_HANDLE_RET \ | ||
254 | if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \ | ||
255 | ctr = ctype_get(cts, CTID_DOUBLE); /* FPRs always hold doubles. */ | ||
256 | |||
257 | #elif LJ_TARGET_PPCSPE | ||
258 | /* -- PPC/SPE calling conventions ----------------------------------------- */ | ||
259 | |||
260 | #define CCALL_HANDLE_STRUCTRET \ | ||
261 | cc->retref = 1; /* Return all structs by reference. */ \ | ||
262 | cc->gpr[ngpr++] = (GPRArg)dp; | ||
263 | |||
264 | #define CCALL_HANDLE_COMPLEXRET \ | ||
265 | /* Complex values are returned in 2 or 4 GPRs. */ \ | ||
266 | cc->retref = 0; | ||
267 | |||
268 | #define CCALL_HANDLE_COMPLEXRET2 \ | ||
269 | memcpy(dp, sp, ctr->size); /* Copy complex from GPRs. */ | ||
270 | |||
271 | #define CCALL_HANDLE_STRUCTARG \ | ||
272 | rp = cdataptr(lj_cdata_new(cts, did, sz)); \ | ||
273 | sz = CTSIZE_PTR; /* Pass all structs by reference. */ | ||
274 | |||
275 | #define CCALL_HANDLE_COMPLEXARG \ | ||
276 | /* Pass complex by value in 2 or 4 GPRs. */ | ||
277 | |||
278 | /* PPC/SPE has a softfp ABI. */ | ||
279 | #define CCALL_HANDLE_REGARG \ | ||
280 | if (n > 1) { /* Doesn't fit in a single GPR? */ \ | ||
281 | lua_assert(n == 2 || n == 4); /* int64_t, double or complex (float). */ \ | ||
282 | if (n == 2) \ | ||
283 | ngpr = (ngpr + 1u) & ~1u; /* Only align 64 bit value to regpair. */ \ | ||
284 | else if (ngpr + n > maxgpr) \ | ||
285 | ngpr = maxgpr; /* Prevent reordering. */ \ | ||
286 | } \ | ||
287 | if (ngpr + n <= maxgpr) { \ | ||
288 | dp = &cc->gpr[ngpr]; \ | ||
289 | ngpr += n; \ | ||
290 | goto done; \ | ||
291 | } | ||
292 | |||
293 | #else | ||
294 | #error "Missing calling convention definitions for this architecture" | ||
295 | #endif | ||
296 | |||
297 | #ifndef CCALL_HANDLE_STRUCTRET2 | ||
298 | #define CCALL_HANDLE_STRUCTRET2 \ | ||
299 | memcpy(dp, sp, ctr->size); /* Copy struct return value from GPRs. */ | ||
300 | #endif | ||
301 | |||
302 | /* -- x64 struct classification ------------------------------------------- */ | ||
303 | |||
304 | #if LJ_TARGET_X64 && !LJ_ABI_WIN | ||
305 | |||
306 | /* Register classes for x64 struct classification. */ | ||
307 | #define CCALL_RCL_INT 1 | ||
308 | #define CCALL_RCL_SSE 2 | ||
309 | #define CCALL_RCL_MEM 4 | ||
310 | /* NYI: classify vectors. */ | ||
311 | |||
312 | static int ccall_classify_struct(CTState *cts, CType *ct, int *rcl, CTSize ofs); | ||
313 | |||
314 | /* Classify a C type. */ | ||
315 | static void ccall_classify_ct(CTState *cts, CType *ct, int *rcl, CTSize ofs) | ||
316 | { | ||
317 | if (ctype_isarray(ct->info)) { | ||
318 | CType *cct = ctype_rawchild(cts, ct); | ||
319 | CTSize eofs, esz = cct->size, asz = ct->size; | ||
320 | for (eofs = 0; eofs < asz; eofs += esz) | ||
321 | ccall_classify_ct(cts, cct, rcl, ofs+eofs); | ||
322 | } else if (ctype_isstruct(ct->info)) { | ||
323 | ccall_classify_struct(cts, ct, rcl, ofs); | ||
324 | } else { | ||
325 | int cl = ctype_isfp(ct->info) ? CCALL_RCL_SSE : CCALL_RCL_INT; | ||
326 | lua_assert(ctype_hassize(ct->info)); | ||
327 | if ((ofs & (ct->size-1))) cl = CCALL_RCL_MEM; /* Unaligned. */ | ||
328 | rcl[(ofs >= 8)] |= cl; | ||
329 | } | ||
330 | } | ||
331 | |||
332 | /* Recursively classify a struct based on its fields. */ | ||
333 | static int ccall_classify_struct(CTState *cts, CType *ct, int *rcl, CTSize ofs) | ||
334 | { | ||
335 | if (ct->size > 16) return CCALL_RCL_MEM; /* Too big, gets memory class. */ | ||
336 | while (ct->sib) { | ||
337 | CTSize fofs; | ||
338 | ct = ctype_get(cts, ct->sib); | ||
339 | fofs = ofs+ct->size; | ||
340 | if (ctype_isfield(ct->info)) | ||
341 | ccall_classify_ct(cts, ctype_rawchild(cts, ct), rcl, fofs); | ||
342 | else if (ctype_isbitfield(ct->info)) | ||
343 | rcl[(fofs >= 8)] |= CCALL_RCL_INT; /* NYI: unaligned bitfields? */ | ||
344 | else if (ctype_isxattrib(ct->info, CTA_SUBTYPE)) | ||
345 | ccall_classify_struct(cts, ctype_child(cts, ct), rcl, fofs); | ||
346 | } | ||
347 | return ((rcl[0]|rcl[1]) & CCALL_RCL_MEM); /* Memory class? */ | ||
348 | } | ||
349 | |||
350 | /* Try to split up a small struct into registers. */ | ||
351 | static int ccall_struct_reg(CCallState *cc, GPRArg *dp, int *rcl) | ||
352 | { | ||
353 | MSize ngpr = cc->ngpr, nfpr = cc->nfpr; | ||
354 | uint32_t i; | ||
355 | for (i = 0; i < 2; i++) { | ||
356 | lua_assert(!(rcl[i] & CCALL_RCL_MEM)); | ||
357 | if ((rcl[i] & CCALL_RCL_INT)) { /* Integer class takes precedence. */ | ||
358 | if (ngpr >= CCALL_NARG_GPR) return 1; /* Register overflow. */ | ||
359 | cc->gpr[ngpr++] = dp[i]; | ||
360 | } else if ((rcl[i] & CCALL_RCL_SSE)) { | ||
361 | if (nfpr >= CCALL_NARG_FPR) return 1; /* Register overflow. */ | ||
362 | cc->fpr[nfpr++].l[0] = dp[i]; | ||
363 | } | ||
364 | } | ||
365 | cc->ngpr = ngpr; cc->nfpr = nfpr; | ||
366 | return 0; /* Ok. */ | ||
367 | } | ||
368 | |||
369 | /* Pass a small struct argument. */ | ||
370 | static int ccall_struct_arg(CCallState *cc, CTState *cts, CType *d, int *rcl, | ||
371 | TValue *o, int narg) | ||
372 | { | ||
373 | GPRArg dp[2]; | ||
374 | dp[0] = dp[1] = 0; | ||
375 | /* Convert to temp. struct. */ | ||
376 | lj_cconv_ct_tv(cts, d, (uint8_t *)dp, o, CCF_ARG(narg)); | ||
377 | if (ccall_struct_reg(cc, dp, rcl)) { /* Register overflow? Pass on stack. */ | ||
378 | MSize nsp = cc->nsp, n = rcl[1] ? 2 : 1; | ||
379 | if (nsp + n > CCALL_MAXSTACK) return 1; /* Too many arguments. */ | ||
380 | cc->nsp = nsp + n; | ||
381 | memcpy(&cc->stack[nsp], dp, n*CTSIZE_PTR); | ||
382 | } | ||
383 | return 0; /* Ok. */ | ||
384 | } | ||
385 | |||
386 | /* Combine returned small struct. */ | ||
387 | static void ccall_struct_ret(CCallState *cc, int *rcl, uint8_t *dp, CTSize sz) | ||
388 | { | ||
389 | GPRArg sp[2]; | ||
390 | MSize ngpr = 0, nfpr = 0; | ||
391 | uint32_t i; | ||
392 | for (i = 0; i < 2; i++) { | ||
393 | if ((rcl[i] & CCALL_RCL_INT)) { /* Integer class takes precedence. */ | ||
394 | sp[i] = cc->gpr[ngpr++]; | ||
395 | } else if ((rcl[i] & CCALL_RCL_SSE)) { | ||
396 | sp[i] = cc->fpr[nfpr++].l[0]; | ||
397 | } | ||
398 | } | ||
399 | memcpy(dp, sp, sz); | ||
400 | } | ||
401 | #endif | ||
402 | |||
403 | /* -- Common C call handling ---------------------------------------------- */ | ||
404 | |||
405 | /* Infer the destination CTypeID for a vararg argument. */ | ||
406 | CTypeID lj_ccall_ctid_vararg(CTState *cts, cTValue *o) | ||
407 | { | ||
408 | if (tvisnumber(o)) { | ||
409 | return CTID_DOUBLE; | ||
410 | } else if (tviscdata(o)) { | ||
411 | CTypeID id = cdataV(o)->typeid; | ||
412 | CType *s = ctype_get(cts, id); | ||
413 | if (ctype_isrefarray(s->info)) { | ||
414 | return lj_ctype_intern(cts, | ||
415 | CTINFO(CT_PTR, CTALIGN_PTR|ctype_cid(s->info)), CTSIZE_PTR); | ||
416 | } else if (ctype_isstruct(s->info) || ctype_isfunc(s->info)) { | ||
417 | /* NYI: how to pass a struct by value in a vararg argument? */ | ||
418 | return lj_ctype_intern(cts, CTINFO(CT_PTR, CTALIGN_PTR|id), CTSIZE_PTR); | ||
419 | } else if (ctype_isfp(s->info) && s->size == sizeof(float)) { | ||
420 | return CTID_DOUBLE; | ||
421 | } else { | ||
422 | return id; | ||
423 | } | ||
424 | } else if (tvisstr(o)) { | ||
425 | return CTID_P_CCHAR; | ||
426 | } else if (tvisbool(o)) { | ||
427 | return CTID_BOOL; | ||
428 | } else { | ||
429 | return CTID_P_VOID; | ||
430 | } | ||
431 | } | ||
432 | |||
433 | /* Setup arguments for C call. */ | ||
434 | static int ccall_set_args(lua_State *L, CTState *cts, CType *ct, | ||
435 | CCallState *cc) | ||
436 | { | ||
437 | int gcsteps = 0; | ||
438 | TValue *o, *top = L->top; | ||
439 | CTypeID fid; | ||
440 | CType *ctr; | ||
441 | MSize maxgpr, ngpr = 0, nsp = 0, narg; | ||
442 | #if CCALL_NARG_FPR | ||
443 | MSize nfpr = 0; | ||
444 | #endif | ||
445 | |||
446 | /* Clear unused regs to get some determinism in case of misdeclaration. */ | ||
447 | memset(cc->gpr, 0, sizeof(cc->gpr)); | ||
448 | #if CCALL_NUM_FPR | ||
449 | memset(cc->fpr, 0, sizeof(cc->fpr)); | ||
450 | #endif | ||
451 | |||
452 | #if LJ_TARGET_X86 | ||
453 | /* x86 has several different calling conventions. */ | ||
454 | cc->resx87 = 0; | ||
455 | switch (ctype_cconv(ct->info)) { | ||
456 | case CTCC_FASTCALL: maxgpr = 2; break; | ||
457 | case CTCC_THISCALL: maxgpr = 1; break; | ||
458 | default: maxgpr = 0; break; | ||
459 | } | ||
460 | #else | ||
461 | maxgpr = CCALL_NARG_GPR; | ||
462 | #endif | ||
463 | |||
464 | /* Perform required setup for some result types. */ | ||
465 | ctr = ctype_rawchild(cts, ct); | ||
466 | if (ctype_isvector(ctr->info)) { | ||
467 | if (!(CCALL_VECTOR_REG && (ctr->size == 8 || ctr->size == 16))) | ||
468 | goto err_nyi; | ||
469 | } else if (ctype_iscomplex(ctr->info) || ctype_isstruct(ctr->info)) { | ||
470 | /* Preallocate cdata object and anchor it after arguments. */ | ||
471 | CTSize sz = ctr->size; | ||
472 | GCcdata *cd = lj_cdata_new(cts, ctype_cid(ct->info), sz); | ||
473 | void *dp = cdataptr(cd); | ||
474 | setcdataV(L, L->top++, cd); | ||
475 | if (ctype_isstruct(ctr->info)) { | ||
476 | CCALL_HANDLE_STRUCTRET | ||
477 | } else { | ||
478 | CCALL_HANDLE_COMPLEXRET | ||
479 | } | ||
480 | #if LJ_TARGET_X86 | ||
481 | } else if (ctype_isfp(ctr->info)) { | ||
482 | cc->resx87 = ctr->size == sizeof(float) ? 1 : 2; | ||
483 | #endif | ||
484 | } | ||
485 | |||
486 | /* Skip initial attributes. */ | ||
487 | fid = ct->sib; | ||
488 | while (fid) { | ||
489 | CType *ctf = ctype_get(cts, fid); | ||
490 | if (!ctype_isattrib(ctf->info)) break; | ||
491 | fid = ctf->sib; | ||
492 | } | ||
493 | |||
494 | /* Walk through all passed arguments. */ | ||
495 | for (o = L->base+1, narg = 1; o < top; o++, narg++) { | ||
496 | CTypeID did; | ||
497 | CType *d; | ||
498 | CTSize sz; | ||
499 | MSize n, isfp = 0, isva = 0; | ||
500 | void *dp, *rp = NULL; | ||
501 | |||
502 | if (fid) { /* Get argument type from field. */ | ||
503 | CType *ctf = ctype_get(cts, fid); | ||
504 | fid = ctf->sib; | ||
505 | lua_assert(ctype_isfield(ctf->info)); | ||
506 | did = ctype_cid(ctf->info); | ||
507 | } else { | ||
508 | if (!(ct->info & CTF_VARARG)) | ||
509 | lj_err_caller(L, LJ_ERR_FFI_NUMARG); /* Too many arguments. */ | ||
510 | did = lj_ccall_ctid_vararg(cts, o); /* Infer vararg type. */ | ||
511 | isva = 1; | ||
512 | } | ||
513 | d = ctype_raw(cts, did); | ||
514 | sz = d->size; | ||
515 | |||
516 | /* Find out how (by value/ref) and where (GPR/FPR) to pass an argument. */ | ||
517 | if (ctype_isnum(d->info)) { | ||
518 | if (sz > 8) goto err_nyi; | ||
519 | if ((d->info & CTF_FP)) | ||
520 | isfp = 1; | ||
521 | } else if (ctype_isvector(d->info)) { | ||
522 | if (CCALL_VECTOR_REG && (sz == 8 || sz == 16)) | ||
523 | isfp = 1; | ||
524 | else | ||
525 | goto err_nyi; | ||
526 | } else if (ctype_isstruct(d->info)) { | ||
527 | CCALL_HANDLE_STRUCTARG | ||
528 | } else if (ctype_iscomplex(d->info)) { | ||
529 | CCALL_HANDLE_COMPLEXARG | ||
530 | } else { | ||
531 | sz = CTSIZE_PTR; | ||
532 | } | ||
533 | sz = (sz + CTSIZE_PTR-1) & ~(CTSIZE_PTR-1); | ||
534 | n = sz / CTSIZE_PTR; /* Number of GPRs or stack slots needed. */ | ||
535 | |||
536 | CCALL_HANDLE_REGARG /* Handle register arguments. */ | ||
537 | |||
538 | /* Otherwise pass argument on stack. */ | ||
539 | if (CCALL_ALIGN_STACKARG && !rp && (d->info & CTF_ALIGN) > CTALIGN_PTR) { | ||
540 | MSize align = (1u << ctype_align(d->info-CTALIGN_PTR)) -1; | ||
541 | nsp = (nsp + align) & ~align; /* Align argument on stack. */ | ||
542 | } | ||
543 | if (nsp + n > CCALL_MAXSTACK) { /* Too many arguments. */ | ||
544 | err_nyi: | ||
545 | lj_err_caller(L, LJ_ERR_FFI_NYICALL); | ||
546 | } | ||
547 | dp = &cc->stack[nsp]; | ||
548 | nsp += n; | ||
549 | isva = 0; | ||
550 | |||
551 | done: | ||
552 | if (rp) { /* Pass by reference. */ | ||
553 | gcsteps++; | ||
554 | *(void **)dp = rp; | ||
555 | dp = rp; | ||
556 | } | ||
557 | lj_cconv_ct_tv(cts, d, (uint8_t *)dp, o, CCF_ARG(narg)); | ||
558 | /* Extend passed integers to 32 bits at least. */ | ||
559 | if (ctype_isinteger_or_bool(d->info) && d->size < 4) { | ||
560 | if (d->info & CTF_UNSIGNED) | ||
561 | *(uint32_t *)dp = d->size == 1 ? (uint32_t)*(uint8_t *)dp : | ||
562 | (uint32_t)*(uint16_t *)dp; | ||
563 | else | ||
564 | *(int32_t *)dp = d->size == 1 ? (int32_t)*(int8_t *)dp : | ||
565 | (int32_t)*(int16_t *)dp; | ||
566 | } | ||
567 | #if LJ_TARGET_X64 && LJ_ABI_WIN | ||
568 | if (isva) { /* Windows/x64 mirrors varargs in both register sets. */ | ||
569 | if (nfpr == ngpr) | ||
570 | cc->gpr[ngpr-1] = cc->fpr[ngpr-1].l[0]; | ||
571 | else | ||
572 | cc->fpr[ngpr-1].l[0] = cc->gpr[ngpr-1]; | ||
573 | } | ||
574 | #else | ||
575 | UNUSED(isva); | ||
576 | #endif | ||
577 | #if LJ_TARGET_X64 && !LJ_ABI_WIN | ||
578 | if (isfp == 2 && n == 2 && (uint8_t *)dp == (uint8_t *)&cc->fpr[nfpr-2]) { | ||
579 | cc->fpr[nfpr-1].d[0] = cc->fpr[nfpr-2].d[1]; /* Split complex double. */ | ||
580 | cc->fpr[nfpr-2].d[1] = 0; | ||
581 | } | ||
582 | #else | ||
583 | UNUSED(isfp); | ||
584 | #endif | ||
585 | } | ||
586 | if (fid) lj_err_caller(L, LJ_ERR_FFI_NUMARG); /* Too few arguments. */ | ||
587 | |||
588 | #if LJ_TARGET_X64 || LJ_TARGET_PPC | ||
589 | cc->nfpr = nfpr; /* Required for vararg functions. */ | ||
590 | #endif | ||
591 | cc->nsp = nsp; | ||
592 | cc->spadj = (CCALL_SPS_FREE + CCALL_SPS_EXTRA)*CTSIZE_PTR; | ||
593 | if (nsp > CCALL_SPS_FREE) | ||
594 | cc->spadj += (((nsp-CCALL_SPS_FREE)*CTSIZE_PTR + 15u) & ~15u); | ||
595 | return gcsteps; | ||
596 | } | ||
597 | |||
598 | /* Get results from C call. */ | ||
599 | static int ccall_get_results(lua_State *L, CTState *cts, CType *ct, | ||
600 | CCallState *cc, int *ret) | ||
601 | { | ||
602 | CType *ctr = ctype_rawchild(cts, ct); | ||
603 | uint8_t *sp = (uint8_t *)&cc->gpr[0]; | ||
604 | if (ctype_isvoid(ctr->info)) { | ||
605 | *ret = 0; /* Zero results. */ | ||
606 | return 0; /* No additional GC step. */ | ||
607 | } | ||
608 | *ret = 1; /* One result. */ | ||
609 | if (ctype_isstruct(ctr->info)) { | ||
610 | /* Return cdata object which is already on top of stack. */ | ||
611 | if (!cc->retref) { | ||
612 | void *dp = cdataptr(cdataV(L->top-1)); /* Use preallocated object. */ | ||
613 | CCALL_HANDLE_STRUCTRET2 | ||
614 | } | ||
615 | return 1; /* One GC step. */ | ||
616 | } | ||
617 | if (ctype_iscomplex(ctr->info)) { | ||
618 | /* Return cdata object which is already on top of stack. */ | ||
619 | void *dp = cdataptr(cdataV(L->top-1)); /* Use preallocated object. */ | ||
620 | CCALL_HANDLE_COMPLEXRET2 | ||
621 | return 1; /* One GC step. */ | ||
622 | } | ||
623 | if (LJ_BE && ctype_isinteger_or_bool(ctr->info) && ctr->size < CTSIZE_PTR) | ||
624 | sp += (CTSIZE_PTR - ctr->size); | ||
625 | #ifdef CCALL_HANDLE_RET | ||
626 | CCALL_HANDLE_RET | ||
627 | #endif | ||
628 | #if CCALL_NUM_FPR | ||
629 | if (ctype_isfp(ctr->info) || ctype_isvector(ctr->info)) | ||
630 | sp = (uint8_t *)&cc->fpr[0]; | ||
631 | #endif | ||
632 | /* No reference types end up here, so there's no need for the CTypeID. */ | ||
633 | lua_assert(!(ctype_isrefarray(ctr->info) || ctype_isstruct(ctr->info))); | ||
634 | if (ctype_isenum(ctr->info)) ctr = ctype_child(cts, ctr); | ||
635 | return lj_cconv_tv_ct(cts, ctr, 0, L->top-1, sp); | ||
636 | } | ||
637 | |||
638 | /* Call C function. */ | ||
639 | int lj_ccall_func(lua_State *L, GCcdata *cd) | ||
640 | { | ||
641 | CTState *cts = ctype_cts(L); | ||
642 | CType *ct = ctype_raw(cts, cd->typeid); | ||
643 | CTSize sz = CTSIZE_PTR; | ||
644 | if (ctype_isptr(ct->info)) { | ||
645 | sz = ct->size; | ||
646 | ct = ctype_rawchild(cts, ct); | ||
647 | } | ||
648 | if (ctype_isfunc(ct->info)) { | ||
649 | CCallState cc; | ||
650 | int gcsteps, ret; | ||
651 | cc.func = (void (*)(void))cdata_getptr(cdataptr(cd), sz); | ||
652 | gcsteps = ccall_set_args(L, cts, ct, &cc); | ||
653 | cts->cb.slot = ~0u; | ||
654 | lj_vm_ffi_call(&cc); | ||
655 | if (cts->cb.slot != ~0u) { /* Blacklist function that called a callback. */ | ||
656 | TValue tv; | ||
657 | setlightudV(&tv, (void *)cc.func); | ||
658 | setboolV(lj_tab_set(L, cts->miscmap, &tv), 1); | ||
659 | } | ||
660 | gcsteps += ccall_get_results(L, cts, ct, &cc, &ret); | ||
661 | #if LJ_TARGET_X86 && LJ_ABI_WIN | ||
662 | /* Automatically detect __stdcall and fix up C function declaration. */ | ||
663 | if (cc.spadj && ctype_cconv(ct->info) == CTCC_CDECL) { | ||
664 | CTF_INSERT(ct->info, CCONV, CTCC_STDCALL); | ||
665 | lj_trace_abort(G(L)); | ||
666 | } | ||
667 | #endif | ||
668 | while (gcsteps-- > 0) | ||
669 | lj_gc_check(L); | ||
670 | return ret; | ||
671 | } | ||
672 | return -1; /* Not a function. */ | ||
673 | } | ||
674 | |||
675 | #endif | ||