• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tarantool / luajit / 11139910794

02 Oct 2024 07:45AM UTC coverage: 92.891% (+0.006%) from 92.885%
11139910794

push

github

Buristan
Fix bit op coercion in DUALNUM builds.

Thanks to Sergey Kaplun.

(cherry picked from commit f5fd22203)

The `lj_carith_check64()` function coerces the given number value to the
32-bit wide value. In this case, the 64-bit-wide operands will lose
upper bits.

This patch removes the excess coercion for the DUALNUM mode and drops
the corresponding skipcond introduced for the test in the previous
commit.

Sergey Kaplun:
* added the description and the test for the problem

Part of tarantool/tarantool#10199

5684 of 6026 branches covered (94.32%)

Branch coverage included in aggregate %.

1 of 1 new or added line in 1 file covered. (100.0%)

2 existing lines in 1 file now uncovered.

21679 of 23431 relevant lines covered (92.52%)

2951479.61 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

84.03
/src/lj_ccall.c
1
/*
2
** FFI C call handling.
3
** Copyright (C) 2005-2017 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_tab.h"
13
#include "lj_ctype.h"
14
#include "lj_cconv.h"
15
#include "lj_cdata.h"
16
#include "lj_ccall.h"
17
#include "lj_trace.h"
18

19
/* Target-specific handling of register arguments. */
20
#if LJ_TARGET_X86
21
/* -- x86 calling conventions --------------------------------------------- */
22

23
#if LJ_ABI_WIN
24

25
#define CCALL_HANDLE_STRUCTRET \
26
  /* Return structs bigger than 8 by reference (on stack only). */ \
27
  cc->retref = (sz > 8); \
28
  if (cc->retref) cc->stack[nsp++] = (GPRArg)dp;
29

30
#define CCALL_HANDLE_COMPLEXRET CCALL_HANDLE_STRUCTRET
31

32
#else
33

34
#if LJ_TARGET_OSX
35

36
#define CCALL_HANDLE_STRUCTRET \
37
  /* Return structs of size 1, 2, 4 or 8 in registers. */ \
38
  cc->retref = !(sz == 1 || sz == 2 || sz == 4 || sz == 8); \
39
  if (cc->retref) { \
40
    if (ngpr < maxgpr) \
41
      cc->gpr[ngpr++] = (GPRArg)dp; \
42
    else \
43
      cc->stack[nsp++] = (GPRArg)dp; \
44
  } else {  /* Struct with single FP field ends up in FPR. */ \
45
    cc->resx87 = ccall_classify_struct(cts, ctr); \
46
  }
47

48
#define CCALL_HANDLE_STRUCTRET2 \
49
  if (cc->resx87) sp = (uint8_t *)&cc->fpr[0]; \
50
  memcpy(dp, sp, ctr->size);
51

52
#else
53

54
#define CCALL_HANDLE_STRUCTRET \
55
  cc->retref = 1;  /* Return all structs by reference (in reg or on stack). */ \
56
  if (ngpr < maxgpr) \
57
    cc->gpr[ngpr++] = (GPRArg)dp; \
58
  else \
59
    cc->stack[nsp++] = (GPRArg)dp;
60

61
#endif
62

63
#define CCALL_HANDLE_COMPLEXRET \
64
  /* Return complex float in GPRs and complex double by reference. */ \
65
  cc->retref = (sz > 8); \
66
  if (cc->retref) { \
67
    if (ngpr < maxgpr) \
68
      cc->gpr[ngpr++] = (GPRArg)dp; \
69
    else \
70
      cc->stack[nsp++] = (GPRArg)dp; \
71
  }
72

73
#endif
74

75
#define CCALL_HANDLE_COMPLEXRET2 \
76
  if (!cc->retref) \
77
    *(int64_t *)dp = *(int64_t *)sp;  /* Copy complex float from GPRs. */
78

79
#define CCALL_HANDLE_STRUCTARG \
80
  ngpr = maxgpr;  /* Pass all structs by value on the stack. */
81

82
#define CCALL_HANDLE_COMPLEXARG \
83
  isfp = 1;  /* Pass complex by value on stack. */
84

85
#define CCALL_HANDLE_REGARG \
86
  if (!isfp) {  /* Only non-FP values may be passed in registers. */ \
87
    if (n > 1) {  /* Anything > 32 bit is passed on the stack. */ \
88
      if (!LJ_ABI_WIN) ngpr = maxgpr;  /* Prevent reordering. */ \
89
    } else if (ngpr + 1 <= maxgpr) { \
90
      dp = &cc->gpr[ngpr]; \
91
      ngpr += n; \
92
      goto done; \
93
    } \
94
  }
95

96
#elif LJ_TARGET_X64 && LJ_ABI_WIN
97
/* -- Windows/x64 calling conventions ------------------------------------- */
98

99
#define CCALL_HANDLE_STRUCTRET \
100
  /* Return structs of size 1, 2, 4 or 8 in a GPR. */ \
101
  cc->retref = !(sz == 1 || sz == 2 || sz == 4 || sz == 8); \
102
  if (cc->retref) cc->gpr[ngpr++] = (GPRArg)dp;
103

104
#define CCALL_HANDLE_COMPLEXRET CCALL_HANDLE_STRUCTRET
105

106
#define CCALL_HANDLE_COMPLEXRET2 \
107
  if (!cc->retref) \
108
    *(int64_t *)dp = *(int64_t *)sp;  /* Copy complex float from GPRs. */
109

110
#define CCALL_HANDLE_STRUCTARG \
111
  /* Pass structs of size 1, 2, 4 or 8 in a GPR by value. */ \
112
  if (!(sz == 1 || sz == 2 || sz == 4 || sz == 8)) { \
113
    rp = cdataptr(lj_cdata_new(cts, did, sz)); \
114
    sz = CTSIZE_PTR;  /* Pass all other structs by reference. */ \
115
  }
116

117
#define CCALL_HANDLE_COMPLEXARG \
118
  /* Pass complex float in a GPR and complex double by reference. */ \
119
  if (sz != 2*sizeof(float)) { \
120
    rp = cdataptr(lj_cdata_new(cts, did, sz)); \
121
    sz = CTSIZE_PTR; \
122
  }
123

124
/* Windows/x64 argument registers are strictly positional (use ngpr). */
125
#define CCALL_HANDLE_REGARG \
126
  if (isfp) { \
127
    if (ngpr < maxgpr) { dp = &cc->fpr[ngpr++]; nfpr = ngpr; goto done; } \
128
  } else { \
129
    if (ngpr < maxgpr) { dp = &cc->gpr[ngpr++]; goto done; } \
130
  }
131

132
#elif LJ_TARGET_X64
133
/* -- POSIX/x64 calling conventions --------------------------------------- */
134

135
#define CCALL_HANDLE_STRUCTRET \
136
  int rcl[2]; rcl[0] = rcl[1] = 0; \
137
  if (ccall_classify_struct(cts, ctr, rcl, 0)) { \
138
    cc->retref = 1;  /* Return struct by reference. */ \
139
    cc->gpr[ngpr++] = (GPRArg)dp; \
140
  } else { \
141
    cc->retref = 0;  /* Return small structs in registers. */ \
142
  }
143

144
#define CCALL_HANDLE_STRUCTRET2 \
145
  int rcl[2]; rcl[0] = rcl[1] = 0; \
146
  ccall_classify_struct(cts, ctr, rcl, 0); \
147
  ccall_struct_ret(cc, rcl, dp, ctr->size);
148

149
#define CCALL_HANDLE_COMPLEXRET \
150
  /* Complex values are returned in one or two FPRs. */ \
151
  cc->retref = 0;
152

153
#define CCALL_HANDLE_COMPLEXRET2 \
154
  if (ctr->size == 2*sizeof(float)) {  /* Copy complex float from FPR. */ \
155
    *(int64_t *)dp = cc->fpr[0].l[0]; \
156
  } else {  /* Copy non-contiguous complex double from FPRs. */ \
157
    ((int64_t *)dp)[0] = cc->fpr[0].l[0]; \
158
    ((int64_t *)dp)[1] = cc->fpr[1].l[0]; \
159
  }
160

161
#define CCALL_HANDLE_STRUCTARG \
162
  int rcl[2]; rcl[0] = rcl[1] = 0; \
163
  if (!ccall_classify_struct(cts, d, rcl, 0)) { \
164
    cc->nsp = nsp; cc->ngpr = ngpr; cc->nfpr = nfpr; \
165
    if (ccall_struct_arg(cc, cts, d, rcl, o, narg)) goto err_nyi; \
166
    nsp = cc->nsp; ngpr = cc->ngpr; nfpr = cc->nfpr; \
167
    continue; \
168
  }  /* Pass all other structs by value on stack. */
169

170
#define CCALL_HANDLE_COMPLEXARG \
171
  isfp = 2;  /* Pass complex in FPRs or on stack. Needs postprocessing. */
172

173
#define CCALL_HANDLE_REGARG \
174
  if (isfp) {  /* Try to pass argument in FPRs. */ \
175
    int n2 = ctype_isvector(d->info) ? 1 : n; \
176
    if (nfpr + n2 <= CCALL_NARG_FPR) { \
177
      dp = &cc->fpr[nfpr]; \
178
      nfpr += n2; \
179
      goto done; \
180
    } \
181
  } else {  /* Try to pass argument in GPRs. */ \
182
    /* Note that reordering is explicitly allowed in the x64 ABI. */ \
183
    if (n <= 2 && ngpr + n <= maxgpr) { \
184
      dp = &cc->gpr[ngpr]; \
185
      ngpr += n; \
186
      goto done; \
187
    } \
188
  }
189

190
#elif LJ_TARGET_ARM
191
/* -- ARM calling conventions --------------------------------------------- */
192

193
#if LJ_ABI_SOFTFP
194

195
#define CCALL_HANDLE_STRUCTRET \
196
  /* Return structs of size <= 4 in a GPR. */ \
197
  cc->retref = !(sz <= 4); \
198
  if (cc->retref) cc->gpr[ngpr++] = (GPRArg)dp;
199

200
#define CCALL_HANDLE_COMPLEXRET \
201
  cc->retref = 1;  /* Return all complex values by reference. */ \
202
  cc->gpr[ngpr++] = (GPRArg)dp;
203

204
#define CCALL_HANDLE_COMPLEXRET2 \
205
  UNUSED(dp); /* Nothing to do. */
206

207
#define CCALL_HANDLE_STRUCTARG \
208
  /* Pass all structs by value in registers and/or on the stack. */
209

210
#define CCALL_HANDLE_COMPLEXARG \
211
  /* Pass complex by value in 2 or 4 GPRs. */
212

213
#define CCALL_HANDLE_REGARG_FP1
214
#define CCALL_HANDLE_REGARG_FP2
215

216
#else
217

218
#define CCALL_HANDLE_STRUCTRET \
219
  cc->retref = !ccall_classify_struct(cts, ctr, ct); \
220
  if (cc->retref) cc->gpr[ngpr++] = (GPRArg)dp;
221

222
#define CCALL_HANDLE_STRUCTRET2 \
223
  if (ccall_classify_struct(cts, ctr, ct) > 1) sp = (uint8_t *)&cc->fpr[0]; \
224
  memcpy(dp, sp, ctr->size);
225

226
#define CCALL_HANDLE_COMPLEXRET \
227
  if (!(ct->info & CTF_VARARG)) cc->retref = 0;  /* Return complex in FPRs. */
228

229
#define CCALL_HANDLE_COMPLEXRET2 \
230
  if (!(ct->info & CTF_VARARG)) memcpy(dp, &cc->fpr[0], ctr->size);
231

232
#define CCALL_HANDLE_STRUCTARG \
233
  isfp = (ccall_classify_struct(cts, d, ct) > 1);
234
  /* Pass all structs by value in registers and/or on the stack. */
235

236
#define CCALL_HANDLE_COMPLEXARG \
237
  isfp = 1;  /* Pass complex by value in FPRs or on stack. */
238

239
#define CCALL_HANDLE_REGARG_FP1 \
240
  if (isfp && !(ct->info & CTF_VARARG)) { \
241
    if ((d->info & CTF_ALIGN) > CTALIGN_PTR) { \
242
      if (nfpr + (n >> 1) <= CCALL_NARG_FPR) { \
243
        dp = &cc->fpr[nfpr]; \
244
        nfpr += (n >> 1); \
245
        goto done; \
246
      } \
247
    } else { \
248
      if (sz > 1 && fprodd != nfpr) fprodd = 0; \
249
      if (fprodd) { \
250
        if (2*nfpr+n <= 2*CCALL_NARG_FPR+1) { \
251
          dp = (void *)&cc->fpr[fprodd-1].f[1]; \
252
          nfpr += (n >> 1); \
253
          if ((n & 1)) fprodd = 0; else fprodd = nfpr-1; \
254
          goto done; \
255
        } \
256
      } else { \
257
        if (2*nfpr+n <= 2*CCALL_NARG_FPR) { \
258
          dp = (void *)&cc->fpr[nfpr]; \
259
          nfpr += (n >> 1); \
260
          if ((n & 1)) fprodd = ++nfpr; else fprodd = 0; \
261
          goto done; \
262
        } \
263
      } \
264
    } \
265
    fprodd = 0;  /* No reordering after the first FP value is on stack. */ \
266
  } else {
267

268
#define CCALL_HANDLE_REGARG_FP2        }
269

270
#endif
271

272
#define CCALL_HANDLE_REGARG \
273
  CCALL_HANDLE_REGARG_FP1 \
274
  if ((d->info & CTF_ALIGN) > CTALIGN_PTR) { \
275
    if (ngpr < maxgpr) \
276
      ngpr = (ngpr + 1u) & ~1u;  /* Align to regpair. */ \
277
  } \
278
  if (ngpr < maxgpr) { \
279
    dp = &cc->gpr[ngpr]; \
280
    if (ngpr + n > maxgpr) { \
281
      nsp += ngpr + n - maxgpr;  /* Assumes contiguous gpr/stack fields. */ \
282
      if (nsp > CCALL_MAXSTACK) goto err_nyi;  /* Too many arguments. */ \
283
      ngpr = maxgpr; \
284
    } else { \
285
      ngpr += n; \
286
    } \
287
    goto done; \
288
  } CCALL_HANDLE_REGARG_FP2
289

290
#define CCALL_HANDLE_RET \
291
  if ((ct->info & CTF_VARARG)) sp = (uint8_t *)&cc->gpr[0];
292

293
#elif LJ_TARGET_ARM64
294
/* -- ARM64 calling conventions ------------------------------------------- */
295

296
#define CCALL_HANDLE_STRUCTRET \
297
  cc->retref = !ccall_classify_struct(cts, ctr); \
298
  if (cc->retref) cc->retp = dp;
299

300
#define CCALL_HANDLE_STRUCTRET2 \
301
  unsigned int cl = ccall_classify_struct(cts, ctr); \
302
  if ((cl & 4)) { /* Combine float HFA from separate registers. */ \
303
    CTSize i = (cl >> 8) - 1; \
304
    do { ((uint32_t *)dp)[i] = cc->fpr[i].lo; } while (i--); \
305
  } else { \
306
    if (cl > 1) sp = (uint8_t *)&cc->fpr[0]; \
307
    memcpy(dp, sp, ctr->size); \
308
  }
309

310
#define CCALL_HANDLE_COMPLEXRET \
311
  /* Complex values are returned in one or two FPRs. */ \
312
  cc->retref = 0;
313

314
#define CCALL_HANDLE_COMPLEXRET2 \
315
  if (ctr->size == 2*sizeof(float)) {  /* Copy complex float from FPRs. */ \
316
    ((float *)dp)[0] = cc->fpr[0].f; \
317
    ((float *)dp)[1] = cc->fpr[1].f; \
318
  } else {  /* Copy complex double from FPRs. */ \
319
    ((double *)dp)[0] = cc->fpr[0].d; \
320
    ((double *)dp)[1] = cc->fpr[1].d; \
321
  }
322

323
#define CCALL_HANDLE_STRUCTARG \
324
  unsigned int cl = ccall_classify_struct(cts, d); \
325
  if (cl == 0) {  /* Pass struct by reference. */ \
326
    rp = cdataptr(lj_cdata_new(cts, did, sz)); \
327
    sz = CTSIZE_PTR; \
328
  } else if (cl > 1) {  /* Pass struct in FPRs or on stack. */ \
329
    isfp = (cl & 4) ? 2 : 1; \
330
  }  /* else: Pass struct in GPRs or on stack. */
331

332
#define CCALL_HANDLE_COMPLEXARG \
333
  /* Pass complex by value in separate (!) FPRs or on stack. */ \
334
  isfp = sz == 2*sizeof(float) ? 2 : 1;
335

336
#define CCALL_HANDLE_REGARG \
337
  if (LJ_TARGET_OSX && isva) { \
338
    /* IOS: All variadic arguments are on the stack. */ \
339
  } else if (isfp) {  /* Try to pass argument in FPRs. */ \
340
    int n2 = ctype_isvector(d->info) ? 1 : \
341
             isfp == 1 ? n : (d->size >> (4-isfp)); \
342
    if (nfpr + n2 <= CCALL_NARG_FPR) { \
343
      dp = &cc->fpr[nfpr]; \
344
      nfpr += n2; \
345
      goto done; \
346
    } else { \
347
      nfpr = CCALL_NARG_FPR;  /* Prevent reordering. */ \
348
      if (LJ_TARGET_OSX && d->size < 8) goto err_nyi; \
349
    } \
350
  } else {  /* Try to pass argument in GPRs. */ \
351
    if (!LJ_TARGET_OSX && (d->info & CTF_ALIGN) > CTALIGN_PTR) \
352
      ngpr = (ngpr + 1u) & ~1u;  /* Align to regpair. */ \
353
    if (ngpr + n <= maxgpr) { \
354
      dp = &cc->gpr[ngpr]; \
355
      ngpr += n; \
356
      goto done; \
357
    } else { \
358
      ngpr = maxgpr;  /* Prevent reordering. */ \
359
      if (LJ_TARGET_OSX && d->size < 8) goto err_nyi; \
360
    } \
361
  }
362

363
#if LJ_BE
364
#define CCALL_HANDLE_RET \
365
  if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \
366
    sp = (uint8_t *)&cc->fpr[0].f;
367
#endif
368

369

370
#elif LJ_TARGET_PPC
371
/* -- PPC calling conventions --------------------------------------------- */
372

373
#define CCALL_HANDLE_STRUCTRET \
374
  cc->retref = 1;  /* Return all structs by reference. */ \
375
  cc->gpr[ngpr++] = (GPRArg)dp;
376

377
#define CCALL_HANDLE_COMPLEXRET \
378
  /* Complex values are returned in 2 or 4 GPRs. */ \
379
  cc->retref = 0;
380

381
#define CCALL_HANDLE_COMPLEXRET2 \
382
  memcpy(dp, sp, ctr->size);  /* Copy complex from GPRs. */
383

384
#define CCALL_HANDLE_STRUCTARG \
385
  rp = cdataptr(lj_cdata_new(cts, did, sz)); \
386
  sz = CTSIZE_PTR;  /* Pass all structs by reference. */
387

388
#define CCALL_HANDLE_COMPLEXARG \
389
  /* Pass complex by value in 2 or 4 GPRs. */
390

391
#define CCALL_HANDLE_GPR \
392
  /* Try to pass argument in GPRs. */ \
393
  if (n > 1) { \
394
    /* int64_t or complex (float). */ \
395
    lj_assertL(n == 2 || n == 4, "bad GPR size %d", n); \
396
    if (ctype_isinteger(d->info) || ctype_isfp(d->info)) \
397
      ngpr = (ngpr + 1u) & ~1u;  /* Align int64_t to regpair. */ \
398
    else if (ngpr + n > maxgpr) \
399
      ngpr = maxgpr;  /* Prevent reordering. */ \
400
  } \
401
  if (ngpr + n <= maxgpr) { \
402
    dp = &cc->gpr[ngpr]; \
403
    ngpr += n; \
404
    goto done; \
405
  } \
406

407
#if LJ_ABI_SOFTFP
408
#define CCALL_HANDLE_REGARG  CCALL_HANDLE_GPR
409
#else
410
#define CCALL_HANDLE_REGARG \
411
  if (isfp) {  /* Try to pass argument in FPRs. */ \
412
    if (nfpr + 1 <= CCALL_NARG_FPR) { \
413
      dp = &cc->fpr[nfpr]; \
414
      nfpr += 1; \
415
      d = ctype_get(cts, CTID_DOUBLE);  /* FPRs always hold doubles. */ \
416
      goto done; \
417
    } \
418
  } else { \
419
    CCALL_HANDLE_GPR \
420
  }
421
#endif
422

423
#if !LJ_ABI_SOFTFP
424
#define CCALL_HANDLE_RET \
425
  if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \
426
    ctr = ctype_get(cts, CTID_DOUBLE);  /* FPRs always hold doubles. */
427
#endif
428

429
#elif LJ_TARGET_MIPS32
430
/* -- MIPS o32 calling conventions ---------------------------------------- */
431

432
#define CCALL_HANDLE_STRUCTRET \
433
  cc->retref = 1;  /* Return all structs by reference. */ \
434
  cc->gpr[ngpr++] = (GPRArg)dp;
435

436
#define CCALL_HANDLE_COMPLEXRET \
437
  /* Complex values are returned in 1 or 2 FPRs. */ \
438
  cc->retref = 0;
439

440
#if LJ_ABI_SOFTFP
441
#define CCALL_HANDLE_COMPLEXRET2 \
442
  if (ctr->size == 2*sizeof(float)) {  /* Copy complex float from GPRs. */ \
443
    ((intptr_t *)dp)[0] = cc->gpr[0]; \
444
    ((intptr_t *)dp)[1] = cc->gpr[1]; \
445
  } else {  /* Copy complex double from GPRs. */ \
446
    ((intptr_t *)dp)[0] = cc->gpr[0]; \
447
    ((intptr_t *)dp)[1] = cc->gpr[1]; \
448
    ((intptr_t *)dp)[2] = cc->gpr[2]; \
449
    ((intptr_t *)dp)[3] = cc->gpr[3]; \
450
  }
451
#else
452
#define CCALL_HANDLE_COMPLEXRET2 \
453
  if (ctr->size == 2*sizeof(float)) {  /* Copy complex float from FPRs. */ \
454
    ((float *)dp)[0] = cc->fpr[0].f; \
455
    ((float *)dp)[1] = cc->fpr[1].f; \
456
  } else {  /* Copy complex double from FPRs. */ \
457
    ((double *)dp)[0] = cc->fpr[0].d; \
458
    ((double *)dp)[1] = cc->fpr[1].d; \
459
  }
460
#endif
461

462
#define CCALL_HANDLE_STRUCTARG \
463
  /* Pass all structs by value in registers and/or on the stack. */
464

465
#define CCALL_HANDLE_COMPLEXARG \
466
  /* Pass complex by value in 2 or 4 GPRs. */
467

468
#define CCALL_HANDLE_GPR \
469
  if ((d->info & CTF_ALIGN) > CTALIGN_PTR) \
470
    ngpr = (ngpr + 1u) & ~1u;  /* Align to regpair. */ \
471
  if (ngpr < maxgpr) { \
472
    dp = &cc->gpr[ngpr]; \
473
    if (ngpr + n > maxgpr) { \
474
     nsp += ngpr + n - maxgpr;  /* Assumes contiguous gpr/stack fields. */ \
475
     if (nsp > CCALL_MAXSTACK) goto err_nyi;  /* Too many arguments. */ \
476
     ngpr = maxgpr; \
477
    } else { \
478
     ngpr += n; \
479
    } \
480
    goto done; \
481
  }
482

483
#if !LJ_ABI_SOFTFP        /* MIPS32 hard-float */
484
#define CCALL_HANDLE_REGARG \
485
  if (isfp && nfpr < CCALL_NARG_FPR && !(ct->info & CTF_VARARG)) { \
486
    /* Try to pass argument in FPRs. */ \
487
    dp = n == 1 ? (void *)&cc->fpr[nfpr].f : (void *)&cc->fpr[nfpr].d; \
488
    nfpr++; ngpr += n; \
489
    goto done; \
490
  } else {  /* Try to pass argument in GPRs. */ \
491
    nfpr = CCALL_NARG_FPR; \
492
    CCALL_HANDLE_GPR \
493
  }
494
#else                        /* MIPS32 soft-float */
495
#define CCALL_HANDLE_REGARG CCALL_HANDLE_GPR
496
#endif
497

498
#if !LJ_ABI_SOFTFP
499
/* On MIPS64 soft-float, position of float return values is endian-dependant. */
500
#define CCALL_HANDLE_RET \
501
  if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \
502
    sp = (uint8_t *)&cc->fpr[0].f;
503
#endif
504

505
#elif LJ_TARGET_MIPS64
506
/* -- MIPS n64 calling conventions ---------------------------------------- */
507

508
#define CCALL_HANDLE_STRUCTRET \
509
  cc->retref = !(sz <= 16); \
510
  if (cc->retref) cc->gpr[ngpr++] = (GPRArg)dp;
511

512
#define CCALL_HANDLE_STRUCTRET2 \
513
  ccall_copy_struct(cc, ctr, dp, sp, ccall_classify_struct(cts, ctr, ct));
514

515
#define CCALL_HANDLE_COMPLEXRET \
516
  /* Complex values are returned in 1 or 2 FPRs. */ \
517
  cc->retref = 0;
518

519
#if LJ_ABI_SOFTFP        /* MIPS64 soft-float */
520

521
#define CCALL_HANDLE_COMPLEXRET2 \
522
  if (ctr->size == 2*sizeof(float)) {  /* Copy complex float from GPRs. */ \
523
    ((intptr_t *)dp)[0] = cc->gpr[0]; \
524
  } else {  /* Copy complex double from GPRs. */ \
525
    ((intptr_t *)dp)[0] = cc->gpr[0]; \
526
    ((intptr_t *)dp)[1] = cc->gpr[1]; \
527
  }
528

529
#define CCALL_HANDLE_COMPLEXARG \
530
  /* Pass complex by value in 2 or 4 GPRs. */
531

532
/* Position of soft-float 'float' return value depends on endianess.  */
533
#define CCALL_HANDLE_RET \
534
  if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \
535
    sp = (uint8_t *)cc->gpr + LJ_ENDIAN_SELECT(0, 4);
536

537
#else                        /* MIPS64 hard-float */
538

539
#define CCALL_HANDLE_COMPLEXRET2 \
540
  if (ctr->size == 2*sizeof(float)) {  /* Copy complex float from FPRs. */ \
541
    ((float *)dp)[0] = cc->fpr[0].f; \
542
    ((float *)dp)[1] = cc->fpr[1].f; \
543
  } else {  /* Copy complex double from FPRs. */ \
544
    ((double *)dp)[0] = cc->fpr[0].d; \
545
    ((double *)dp)[1] = cc->fpr[1].d; \
546
  }
547

548
#define CCALL_HANDLE_COMPLEXARG \
549
  if (sz == 2*sizeof(float)) { \
550
    isfp = 2; \
551
    if (ngpr < maxgpr) \
552
      sz *= 2; \
553
  }
554

555
#define CCALL_HANDLE_RET \
556
  if (ctype_isfp(ctr->info) && ctr->size == sizeof(float)) \
557
    sp = (uint8_t *)&cc->fpr[0].f;
558

559
#endif
560

561
#define CCALL_HANDLE_STRUCTARG \
562
  /* Pass all structs by value in registers and/or on the stack. */
563

564
#define CCALL_HANDLE_REGARG \
565
  if (ngpr < maxgpr) { \
566
    dp = &cc->gpr[ngpr]; \
567
    if (ngpr + n > maxgpr) { \
568
      nsp += ngpr + n - maxgpr;  /* Assumes contiguous gpr/stack fields. */ \
569
      if (nsp > CCALL_MAXSTACK) goto err_nyi;  /* Too many arguments. */ \
570
      ngpr = maxgpr; \
571
    } else { \
572
      ngpr += n; \
573
    } \
574
    goto done; \
575
  }
576

577
#else
578
#error "Missing calling convention definitions for this architecture"
579
#endif
580

581
#ifndef CCALL_HANDLE_STRUCTRET2
582
#define CCALL_HANDLE_STRUCTRET2 \
583
  memcpy(dp, sp, ctr->size);  /* Copy struct return value from GPRs. */
584
#endif
585

586
/* -- x86 OSX ABI struct classification ----------------------------------- */
587

588
#if LJ_TARGET_X86 && LJ_TARGET_OSX
589

590
/* Check for struct with single FP field. */
591
static int ccall_classify_struct(CTState *cts, CType *ct)
592
{
593
  CTSize sz = ct->size;
594
  if (!(sz == sizeof(float) || sz == sizeof(double))) return 0;
595
  if ((ct->info & CTF_UNION)) return 0;
596
  while (ct->sib) {
597
    ct = ctype_get(cts, ct->sib);
598
    if (ctype_isfield(ct->info)) {
599
      CType *sct = ctype_rawchild(cts, ct);
600
      if (ctype_isfp(sct->info)) {
601
        if (sct->size == sz)
602
          return (sz >> 2);  /* Return 1 for float or 2 for double. */
603
      } else if (ctype_isstruct(sct->info)) {
604
        if (sct->size)
605
          return ccall_classify_struct(cts, sct);
606
      } else {
607
        break;
608
      }
609
    } else if (ctype_isbitfield(ct->info)) {
610
      break;
611
    } else if (ctype_isxattrib(ct->info, CTA_SUBTYPE)) {
612
      CType *sct = ctype_rawchild(cts, ct);
613
      if (sct->size)
614
        return ccall_classify_struct(cts, sct);
615
    }
616
  }
617
  return 0;
618
}
619

620
#endif
621

622
/* -- x64 struct classification ------------------------------------------- */
623

624
#if LJ_TARGET_X64 && !LJ_ABI_WIN
625

626
/* Register classes for x64 struct classification. */
627
#define CCALL_RCL_INT        1
628
#define CCALL_RCL_SSE        2
629
#define CCALL_RCL_MEM        4
630
/* NYI: classify vectors. */
631

632
static int ccall_classify_struct(CTState *cts, CType *ct, int *rcl, CTSize ofs);
633

634
/* Classify a C type. */
635
static void ccall_classify_ct(CTState *cts, CType *ct, int *rcl, CTSize ofs)
81✔
636
{
637
  if (ctype_isarray(ct->info)) {
81✔
638
    CType *cct = ctype_rawchild(cts, ct);
×
639
    CTSize eofs, esz = cct->size, asz = ct->size;
×
640
    for (eofs = 0; eofs < asz; eofs += esz)
×
641
      ccall_classify_ct(cts, cct, rcl, ofs+eofs);
×
642
  } else if (ctype_isstruct(ct->info)) {
81✔
643
    ccall_classify_struct(cts, ct, rcl, ofs);
×
644
  } else {
645
    int cl = ctype_isfp(ct->info) ? CCALL_RCL_SSE : CCALL_RCL_INT;
81✔
646
    lj_assertCTS(ctype_hassize(ct->info),
81✔
647
                 "classify ctype %08x without size", ct->info);
648
    if ((ofs & (ct->size-1))) cl = CCALL_RCL_MEM;  /* Unaligned. */
81✔
649
    rcl[(ofs >= 8)] |= cl;
143✔
650
  }
651
}
81✔
652

653
/* Recursively classify a struct based on its fields. */
654
static int ccall_classify_struct(CTState *cts, CType *ct, int *rcl, CTSize ofs)
43✔
655
{
656
  if (ct->size > 16) return CCALL_RCL_MEM;  /* Too big, gets memory class. */
43✔
657
  while (ct->sib) {
117✔
658
    CTSize fofs;
81✔
659
    ct = ctype_get(cts, ct->sib);
81✔
660
    fofs = ofs+ct->size;
81✔
661
    if (ctype_isfield(ct->info))
81✔
662
      ccall_classify_ct(cts, ctype_rawchild(cts, ct), rcl, fofs);
81✔
663
    else if (ctype_isbitfield(ct->info))
×
664
      rcl[(fofs >= 8)] |= CCALL_RCL_INT;  /* NYI: unaligned bitfields? */
×
665
    else if (ctype_isxattrib(ct->info, CTA_SUBTYPE))
×
666
      ccall_classify_struct(cts, ctype_rawchild(cts, ct), rcl, fofs);
×
667
  }
668
  return ((rcl[0]|rcl[1]) & CCALL_RCL_MEM);  /* Memory class? */
36✔
669
}
670

671
/* Try to split up a small struct into registers. */
672
static int ccall_struct_reg(CCallState *cc, CTState *cts, GPRArg *dp, int *rcl)
673
{
674
  MSize ngpr = cc->ngpr, nfpr = cc->nfpr;
675
  uint32_t i;
676
  UNUSED(cts);
677
  for (i = 0; i < 2; i++) {
678
    lj_assertCTS(!(rcl[i] & CCALL_RCL_MEM), "pass mem struct in reg");
679
    if ((rcl[i] & CCALL_RCL_INT)) {  /* Integer class takes precedence. */
680
      if (ngpr >= CCALL_NARG_GPR) return 1;  /* Register overflow. */
681
      cc->gpr[ngpr++] = dp[i];
682
    } else if ((rcl[i] & CCALL_RCL_SSE)) {
683
      if (nfpr >= CCALL_NARG_FPR) return 1;  /* Register overflow. */
684
      cc->fpr[nfpr++].l[0] = dp[i];
685
    }
686
  }
687
  cc->ngpr = ngpr; cc->nfpr = nfpr;
688
  return 0;  /* Ok. */
689
}
690

691
/* Pass a small struct argument. */
692
static int ccall_struct_arg(CCallState *cc, CTState *cts, CType *d, int *rcl,
15✔
693
                            TValue *o, int narg)
694
{
695
  GPRArg dp[2];
15✔
696
  dp[0] = dp[1] = 0;
15✔
697
  /* Convert to temp. struct. */
698
  lj_cconv_ct_tv(cts, d, (uint8_t *)dp, o, CCF_ARG(narg));
15✔
699
  if (ccall_struct_reg(cc, cts, dp, rcl)) {
15✔
700
    /* Register overflow? Pass on stack. */
701
    MSize nsp = cc->nsp, n = rcl[1] ? 2 : 1;
×
702
    if (nsp + n > CCALL_MAXSTACK) return 1;  /* Too many arguments. */
×
703
    cc->nsp = nsp + n;
×
704
    memcpy(&cc->stack[nsp], dp, n*CTSIZE_PTR);
×
705
  }
706
  return 0;  /* Ok. */
707
}
708

709
/* Combine returned small struct. */
710
static void ccall_struct_ret(CCallState *cc, int *rcl, uint8_t *dp, CTSize sz)
10✔
711
{
712
  GPRArg sp[2];
10✔
713
  MSize ngpr = 0, nfpr = 0;
10✔
714
  uint32_t i;
10✔
715
  for (i = 0; i < 2; i++) {
30✔
716
    if ((rcl[i] & CCALL_RCL_INT)) {  /* Integer class takes precedence. */
20✔
717
      sp[i] = cc->gpr[ngpr++];
5✔
718
    } else if ((rcl[i] & CCALL_RCL_SSE)) {
15✔
719
      sp[i] = cc->fpr[nfpr++].l[0];
10✔
720
    }
721
  }
722
  memcpy(dp, sp, sz);
10✔
723
}
10✔
724
#endif
725

726
/* -- ARM hard-float ABI struct classification ---------------------------- */
727

728
#if LJ_TARGET_ARM && !LJ_ABI_SOFTFP
729

730
/* Classify a struct based on its fields. */
731
static unsigned int ccall_classify_struct(CTState *cts, CType *ct, CType *ctf)
732
{
733
  CTSize sz = ct->size;
734
  unsigned int r = 0, n = 0, isu = (ct->info & CTF_UNION);
735
  if ((ctf->info & CTF_VARARG)) goto noth;
736
  while (ct->sib) {
737
    CType *sct;
738
    ct = ctype_get(cts, ct->sib);
739
    if (ctype_isfield(ct->info)) {
740
      sct = ctype_rawchild(cts, ct);
741
      if (ctype_isfp(sct->info)) {
742
        r |= sct->size;
743
        if (!isu) n++; else if (n == 0) n = 1;
744
      } else if (ctype_iscomplex(sct->info)) {
745
        r |= (sct->size >> 1);
746
        if (!isu) n += 2; else if (n < 2) n = 2;
747
      } else if (ctype_isstruct(sct->info)) {
748
        goto substruct;
749
      } else {
750
        goto noth;
751
      }
752
    } else if (ctype_isbitfield(ct->info)) {
753
      goto noth;
754
    } else if (ctype_isxattrib(ct->info, CTA_SUBTYPE)) {
755
      sct = ctype_rawchild(cts, ct);
756
    substruct:
757
      if (sct->size > 0) {
758
        unsigned int s = ccall_classify_struct(cts, sct, ctf);
759
        if (s <= 1) goto noth;
760
        r |= (s & 255);
761
        if (!isu) n += (s >> 8); else if (n < (s >>8)) n = (s >> 8);
762
      }
763
    }
764
  }
765
  if ((r == 4 || r == 8) && n <= 4)
766
    return r + (n << 8);
767
noth:  /* Not a homogeneous float/double aggregate. */
768
  return (sz <= 4);  /* Return structs of size <= 4 in a GPR. */
769
}
770

771
#endif
772

773
/* -- ARM64 ABI struct classification ------------------------------------- */
774

775
#if LJ_TARGET_ARM64
776

777
/* Classify a struct based on its fields. */
778
static unsigned int ccall_classify_struct(CTState *cts, CType *ct)
779
{
780
  CTSize sz = ct->size;
781
  unsigned int r = 0, n = 0, isu = (ct->info & CTF_UNION);
782
  while (ct->sib) {
783
    CType *sct;
784
    ct = ctype_get(cts, ct->sib);
785
    if (ctype_isfield(ct->info)) {
786
      sct = ctype_rawchild(cts, ct);
787
      if (ctype_isfp(sct->info)) {
788
        r |= sct->size;
789
        if (!isu) n++; else if (n == 0) n = 1;
790
      } else if (ctype_iscomplex(sct->info)) {
791
        r |= (sct->size >> 1);
792
        if (!isu) n += 2; else if (n < 2) n = 2;
793
      } else if (ctype_isstruct(sct->info)) {
794
        goto substruct;
795
      } else {
796
        goto noth;
797
      }
798
    } else if (ctype_isbitfield(ct->info)) {
799
      goto noth;
800
    } else if (ctype_isxattrib(ct->info, CTA_SUBTYPE)) {
801
      sct = ctype_rawchild(cts, ct);
802
    substruct:
803
      if (sct->size > 0) {
804
        unsigned int s = ccall_classify_struct(cts, sct);
805
        if (s <= 1) goto noth;
806
        r |= (s & 255);
807
        if (!isu) n += (s >> 8); else if (n < (s >>8)) n = (s >> 8);
808
      }
809
    }
810
  }
811
  if ((r == 4 || r == 8) && n <= 4)
812
    return r + (n << 8);
813
noth:  /* Not a homogeneous float/double aggregate. */
814
  return (sz <= 16);  /* Return structs of size <= 16 in GPRs. */
815
}
816

817
#endif
818

819
/* -- MIPS64 ABI struct classification ---------------------------- */
820

821
#if LJ_TARGET_MIPS64
822

823
#define FTYPE_FLOAT        1
824
#define FTYPE_DOUBLE        2
825

826
/* Classify FP fields (max. 2) and their types. */
827
static unsigned int ccall_classify_struct(CTState *cts, CType *ct, CType *ctf)
828
{
829
  int n = 0, ft = 0;
830
  if ((ctf->info & CTF_VARARG) || (ct->info & CTF_UNION))
831
    goto noth;
832
  while (ct->sib) {
833
    CType *sct;
834
    ct = ctype_get(cts, ct->sib);
835
    if (n == 2) {
836
      goto noth;
837
    } else if (ctype_isfield(ct->info)) {
838
      sct = ctype_rawchild(cts, ct);
839
      if (ctype_isfp(sct->info)) {
840
        ft |= (sct->size == 4 ? FTYPE_FLOAT : FTYPE_DOUBLE) << 2*n;
841
        n++;
842
      } else {
843
        goto noth;
844
      }
845
    } else if (ctype_isbitfield(ct->info) ||
846
               ctype_isxattrib(ct->info, CTA_SUBTYPE)) {
847
      goto noth;
848
    }
849
  }
850
  if (n <= 2)
851
    return ft;
852
noth:  /* Not a homogeneous float/double aggregate. */
853
  return 0;  /* Struct is in GPRs. */
854
}
855

856
void ccall_copy_struct(CCallState *cc, CType *ctr, void *dp, void *sp, int ft)
857
{
858
  if (LJ_ABI_SOFTFP ? ft :
859
      ((ft & 3) == FTYPE_FLOAT || (ft >> 2) == FTYPE_FLOAT)) {
860
    int i, ofs = 0;
861
    for (i = 0; ft != 0; i++, ft >>= 2) {
862
      if ((ft & 3) == FTYPE_FLOAT) {
863
#if LJ_ABI_SOFTFP
864
        /* The 2nd FP struct result is in CARG1 (gpr[2]) and not CRET2. */
865
        memcpy((uint8_t *)dp + ofs,
866
               (uint8_t *)&cc->gpr[2*i] + LJ_ENDIAN_SELECT(0, 4), 4);
867
#else
868
        *(float *)((uint8_t *)dp + ofs) = cc->fpr[i].f;
869
#endif
870
        ofs += 4;
871
      } else {
872
        ofs = (ofs + 7) & ~7;  /* 64 bit alignment. */
873
#if LJ_ABI_SOFTFP
874
        *(intptr_t *)((uint8_t *)dp + ofs) = cc->gpr[2*i];
875
#else
876
        *(double *)((uint8_t *)dp + ofs) = cc->fpr[i].d;
877
#endif
878
        ofs += 8;
879
      }
880
    }
881
  } else {
882
#if !LJ_ABI_SOFTFP
883
    if (ft) sp = (uint8_t *)&cc->fpr[0];
884
#endif
885
    memcpy(dp, sp, ctr->size);
886
  }
887
}
888

889
#endif
890

891
/* -- Common C call handling ---------------------------------------------- */
892

893
/* Infer the destination CTypeID for a vararg argument. */
894
CTypeID lj_ccall_ctid_vararg(CTState *cts, cTValue *o)
7✔
895
{
896
  if (tvisnumber(o)) {
7✔
897
    return CTID_DOUBLE;
898
  } else if (tviscdata(o)) {
5✔
899
    CTypeID id = cdataV(o)->ctypeid;
4✔
900
    CType *s = ctype_get(cts, id);
4✔
901
    if (ctype_isrefarray(s->info)) {
4✔
902
      return lj_ctype_intern(cts,
×
903
               CTINFO(CT_PTR, CTALIGN_PTR|ctype_cid(s->info)), CTSIZE_PTR);
×
904
    } else if (ctype_isstruct(s->info) || ctype_isfunc(s->info)) {
4✔
905
      /* NYI: how to pass a struct by value in a vararg argument? */
906
      return lj_ctype_intern(cts, CTINFO(CT_PTR, CTALIGN_PTR|id), CTSIZE_PTR);
×
907
    } else if (ctype_isfp(s->info) && s->size == sizeof(float)) {
4✔
908
      return CTID_DOUBLE;
909
    } else {
910
      return id;
4✔
911
    }
912
  } else if (tvisstr(o)) {
1✔
913
    return CTID_P_CCHAR;
914
  } else if (tvisbool(o)) {
×
915
    return CTID_BOOL;
916
  } else {
917
    return CTID_P_VOID;
×
918
  }
919
}
920

921
/* Setup arguments for C call. */
922
static int ccall_set_args(lua_State *L, CTState *cts, CType *ct,
63,420✔
923
                          CCallState *cc)
924
{
925
  int gcsteps = 0;
63,420✔
926
  TValue *o, *top = L->top;
63,420✔
927
  CTypeID fid;
63,420✔
928
  CType *ctr;
63,420✔
929
  MSize maxgpr, ngpr = 0, nsp = 0, narg;
63,420✔
930
#if CCALL_NARG_FPR
931
  MSize nfpr = 0;
63,420✔
932
#if LJ_TARGET_ARM
933
  MSize fprodd = 0;
934
#endif
935
#endif
936

937
  /* Clear unused regs to get some determinism in case of misdeclaration. */
938
  memset(cc->gpr, 0, sizeof(cc->gpr));
63,420✔
939
#if CCALL_NUM_FPR
940
  memset(cc->fpr, 0, sizeof(cc->fpr));
63,420✔
941
#endif
942

943
#if LJ_TARGET_X86
944
  /* x86 has several different calling conventions. */
945
  cc->resx87 = 0;
946
  switch (ctype_cconv(ct->info)) {
947
  case CTCC_FASTCALL: maxgpr = 2; break;
948
  case CTCC_THISCALL: maxgpr = 1; break;
949
  default: maxgpr = 0; break;
950
  }
951
#else
952
  maxgpr = CCALL_NARG_GPR;
63,420✔
953
#endif
954

955
  /* Perform required setup for some result types. */
956
  ctr = ctype_rawchild(cts, ct);
63,420✔
957
  if (ctype_isvector(ctr->info)) {
63,420✔
958
    if (!(CCALL_VECTOR_REG && (ctr->size == 8 || ctr->size == 16)))
×
959
      goto err_nyi;
×
960
  } else if (ctype_iscomplex(ctr->info) || ctype_isstruct(ctr->info)) {
63,420✔
961
    /* Preallocate cdata object and anchor it after arguments. */
962
    CTSize sz = ctr->size;
20✔
963
    GCcdata *cd = lj_cdata_new(cts, ctype_cid(ct->info), sz);
20✔
964
    void *dp = cdataptr(cd);
20✔
965
    setcdataV(L, L->top++, cd);
20✔
966
    if (ctype_isstruct(ctr->info)) {
20✔
967
      CCALL_HANDLE_STRUCTRET
14✔
968
    } else {
969
      CCALL_HANDLE_COMPLEXRET
6✔
970
    }
971
#if LJ_TARGET_X86
972
  } else if (ctype_isfp(ctr->info)) {
973
    cc->resx87 = ctr->size == sizeof(float) ? 1 : 2;
974
#endif
975
  }
976

977
  /* Skip initial attributes. */
978
  fid = ct->sib;
63,420✔
979
  while (fid) {
64,469✔
980
    CType *ctf = ctype_get(cts, fid);
64,459✔
981
    if (!ctype_isattrib(ctf->info)) break;
64,459✔
982
    fid = ctf->sib;
1,049✔
983
  }
984

985
  /* Walk through all passed arguments. */
986
  for (o = L->base+1, narg = 1; o < top; o++, narg++) {
130,259✔
987
    CTypeID did;
66,840✔
988
    CType *d;
66,840✔
989
    CTSize sz;
66,840✔
990
    MSize n, isfp = 0, isva = 0;
66,840✔
991
    void *dp, *rp = NULL;
66,840✔
992

993
    if (fid) {  /* Get argument type from field. */
66,840✔
994
      CType *ctf = ctype_get(cts, fid);
66,833✔
995
      fid = ctf->sib;
66,833✔
996
      lj_assertL(ctype_isfield(ctf->info), "field expected");
66,833✔
997
      did = ctype_cid(ctf->info);
66,833✔
998
    } else {
999
      if (!(ct->info & CTF_VARARG))
7✔
1000
        lj_err_caller(L, LJ_ERR_FFI_NUMARG);  /* Too many arguments. */
×
1001
      did = lj_ccall_ctid_vararg(cts, o);  /* Infer vararg type. */
7✔
1002
      isva = 1;
7✔
1003
    }
1004
    d = ctype_raw(cts, did);
66,840✔
1005
    sz = d->size;
66,840✔
1006

1007
    /* Find out how (by value/ref) and where (GPR/FPR) to pass an argument. */
1008
    if (ctype_isnum(d->info)) {
66,840✔
1009
      if (sz > 8) goto err_nyi;
4,462✔
1010
      if ((d->info & CTF_FP))
4,462✔
1011
        isfp = 1;
1,678✔
1012
    } else if (ctype_isvector(d->info)) {
62,378✔
1013
      if (CCALL_VECTOR_REG && (sz == 8 || sz == 16))
×
1014
        isfp = 1;
1015
      else
1016
        goto err_nyi;
×
1017
    } else if (ctype_isstruct(d->info)) {
62,378✔
1018
      CCALL_HANDLE_STRUCTARG
19✔
1019
    } else if (ctype_iscomplex(d->info)) {
62,359✔
1020
      CCALL_HANDLE_COMPLEXARG
1021
    } else {
1022
      sz = CTSIZE_PTR;
62,353✔
1023
    }
1024
    sz = (sz + CTSIZE_PTR-1) & ~(CTSIZE_PTR-1);
66,825✔
1025
    n = sz / CTSIZE_PTR;  /* Number of GPRs or stack slots needed. */
66,825✔
1026

1027
    CCALL_HANDLE_REGARG  /* Handle register arguments. */
68,509✔
1028

1029
    /* Otherwise pass argument on stack. */
1030
    if (CCALL_ALIGN_STACKARG && !rp && (d->info & CTF_ALIGN) > CTALIGN_PTR) {
1,171✔
1031
      MSize align = (1u << ctype_align(d->info-CTALIGN_PTR)) -1;
×
1032
      nsp = (nsp + align) & ~align;  /* Align argument on stack. */
×
1033
    }
1034
    if (nsp + n > CCALL_MAXSTACK) {  /* Too many arguments. */
1,171✔
1035
    err_nyi:
×
1036
      lj_err_caller(L, LJ_ERR_FFI_NYICALL);
×
1037
    }
1038
    dp = &cc->stack[nsp];
1,171✔
1039
    nsp += n;
1,171✔
1040
    isva = 0;
1,171✔
1041

1042
  done:
66,825✔
1043
    if (rp) {  /* Pass by reference. */
66,825✔
1044
      gcsteps++;
1045
      *(void **)dp = rp;
1046
      dp = rp;
1047
    }
1048
    lj_cconv_ct_tv(cts, d, (uint8_t *)dp, o, CCF_ARG(narg));
66,825✔
1049
    /* Extend passed integers to 32 bits at least. */
1050
    if (ctype_isinteger_or_bool(d->info) && d->size < 4) {
66,824✔
1051
      if (d->info & CTF_UNSIGNED)
232✔
1052
        *(uint32_t *)dp = d->size == 1 ? (uint32_t)*(uint8_t *)dp :
174✔
1053
                                         (uint32_t)*(uint16_t *)dp;
58✔
1054
      else
1055
        *(int32_t *)dp = d->size == 1 ? (int32_t)*(int8_t *)dp :
174✔
1056
                                        (int32_t)*(int16_t *)dp;
58✔
1057
    }
1058
#if LJ_TARGET_ARM64 && LJ_BE
1059
    if (isfp && d->size == sizeof(float))
1060
      ((float *)dp)[1] = ((float *)dp)[0];  /* Floats occupy high slot. */
1061
#endif
1062
#if LJ_TARGET_MIPS64 || (LJ_TARGET_ARM64 && LJ_BE)
1063
    if ((ctype_isinteger_or_bool(d->info) || ctype_isenum(d->info)
1064
#if LJ_TARGET_MIPS64
1065
         || (isfp && nsp == 0)
1066
#endif
1067
         ) && d->size <= 4) {
1068
      *(int64_t *)dp = (int64_t)*(int32_t *)dp;  /* Sign-extend to 64 bit. */
1069
    }
1070
#endif
1071
#if LJ_TARGET_X64 && LJ_ABI_WIN
1072
    if (isva) {  /* Windows/x64 mirrors varargs in both register sets. */
1073
      if (nfpr == ngpr)
1074
        cc->gpr[ngpr-1] = cc->fpr[ngpr-1].l[0];
1075
      else
1076
        cc->fpr[ngpr-1].l[0] = cc->gpr[ngpr-1];
1077
    }
1078
#else
1079
    UNUSED(isva);
66,824✔
1080
#endif
1081
#if LJ_TARGET_X64 && !LJ_ABI_WIN
1082
    if (isfp == 2 && n == 2 && (uint8_t *)dp == (uint8_t *)&cc->fpr[nfpr-2]) {
66,824✔
1083
      cc->fpr[nfpr-1].d[0] = cc->fpr[nfpr-2].d[1];  /* Split complex double. */
3✔
1084
      cc->fpr[nfpr-2].d[1] = 0;
3✔
1085
    }
1086
#elif LJ_TARGET_ARM64 || (LJ_TARGET_MIPS64 && !LJ_ABI_SOFTFP)
1087
    if (isfp == 2 && (uint8_t *)dp < (uint8_t *)cc->stack) {
1088
      /* Split float HFA or complex float into separate registers. */
1089
      CTSize i = (sz >> 2) - 1;
1090
      do { ((uint64_t *)dp)[i] = ((uint32_t *)dp)[i]; } while (i--);
1091
    }
1092
#else
1093
    UNUSED(isfp);
1094
#endif
1095
  }
1096
  if (fid) lj_err_caller(L, LJ_ERR_FFI_NUMARG);  /* Too few arguments. */
63,419✔
1097

1098
#if LJ_TARGET_X64 || (LJ_TARGET_PPC && !LJ_ABI_SOFTFP)
1099
  cc->nfpr = nfpr;  /* Required for vararg functions. */
63,419✔
1100
#endif
1101
  cc->nsp = nsp;
63,419✔
1102
  cc->spadj = (CCALL_SPS_FREE + CCALL_SPS_EXTRA)*CTSIZE_PTR;
63,419✔
1103
  if (nsp > CCALL_SPS_FREE)
63,419✔
1104
    cc->spadj += (((nsp-CCALL_SPS_FREE)*CTSIZE_PTR + 15u) & ~15u);
266✔
1105
  return gcsteps;
63,419✔
1106
}
1107

1108
/* Get results from C call. */
1109
static int ccall_get_results(lua_State *L, CTState *cts, CType *ct,
1110
                             CCallState *cc, int *ret)
1111
{
1112
  CType *ctr = ctype_rawchild(cts, ct);
1113
  uint8_t *sp = (uint8_t *)&cc->gpr[0];
1114
  if (ctype_isvoid(ctr->info)) {
1115
    *ret = 0;  /* Zero results. */
1116
    return 0;  /* No additional GC step. */
1117
  }
1118
  *ret = 1;  /* One result. */
1119
  if (ctype_isstruct(ctr->info)) {
1120
    /* Return cdata object which is already on top of stack. */
1121
    if (!cc->retref) {
1122
      void *dp = cdataptr(cdataV(L->top-1));  /* Use preallocated object. */
1123
      CCALL_HANDLE_STRUCTRET2
1124
    }
1125
    return 1;  /* One GC step. */
1126
  }
1127
  if (ctype_iscomplex(ctr->info)) {
1128
    /* Return cdata object which is already on top of stack. */
1129
    void *dp = cdataptr(cdataV(L->top-1));  /* Use preallocated object. */
1130
    CCALL_HANDLE_COMPLEXRET2
1131
    return 1;  /* One GC step. */
1132
  }
1133
  if (LJ_BE && ctr->size < CTSIZE_PTR &&
1134
      (ctype_isinteger_or_bool(ctr->info) || ctype_isenum(ctr->info)))
1135
    sp += (CTSIZE_PTR - ctr->size);
1136
#if CCALL_NUM_FPR
1137
  if (ctype_isfp(ctr->info) || ctype_isvector(ctr->info))
1138
    sp = (uint8_t *)&cc->fpr[0];
1139
#endif
1140
#ifdef CCALL_HANDLE_RET
1141
  CCALL_HANDLE_RET
1142
#endif
1143
  /* No reference types end up here, so there's no need for the CTypeID. */
1144
  lj_assertL(!(ctype_isrefarray(ctr->info) || ctype_isstruct(ctr->info)),
1145
             "unexpected reference ctype");
1146
  return lj_cconv_tv_ct(cts, ctr, 0, L->top-1, sp);
1147
}
1148

1149
/* Call C function. */
1150
int lj_ccall_func(lua_State *L, GCcdata *cd)
63,481✔
1151
{
1152
  CTState *cts = ctype_cts(L);
63,481✔
1153
  CType *ct = ctype_raw(cts, cd->ctypeid);
63,481✔
1154
  CTSize sz = CTSIZE_PTR;
63,481✔
1155
  if (ctype_isptr(ct->info)) {
63,481✔
1156
    sz = ct->size;
221✔
1157
    ct = ctype_rawchild(cts, ct);
221✔
1158
  }
1159
  if (ctype_isfunc(ct->info)) {
63,481✔
1160
    CCallState cc;
63,420✔
1161
    int gcsteps, ret;
63,420✔
1162
    cc.func = (void (*)(void))cdata_getptr(cdataptr(cd), sz);
63,420✔
1163
    gcsteps = ccall_set_args(L, cts, ct, &cc);
63,420✔
1164
    ct = (CType *)((intptr_t)ct-(intptr_t)cts->tab);
63,419✔
1165
    cts->cb.slot = ~0u;
63,419✔
1166
    lj_vm_ffi_call(&cc);
63,419✔
1167
    if (cts->cb.slot != ~0u) {  /* Blacklist function that called a callback. */
63,411✔
1168
      TValue tv;
155✔
1169
      tv.u64 = ((uintptr_t)(void *)cc.func >> 2) | U64x(800000000, 00000000);
155✔
1170
      setboolV(lj_tab_set(L, cts->miscmap, &tv), 1);
155✔
1171
    }
1172
    ct = (CType *)((intptr_t)ct+(intptr_t)cts->tab);  /* May be reallocated. */
63,411✔
1173
    gcsteps += ccall_get_results(L, cts, ct, &cc, &ret);
63,411✔
1174
#if LJ_TARGET_X86 && LJ_ABI_WIN
1175
    /* Automatically detect __stdcall and fix up C function declaration. */
1176
    if (cc.spadj && ctype_cconv(ct->info) == CTCC_CDECL) {
1177
      CTF_INSERT(ct->info, CCONV, CTCC_STDCALL);
1178
      lj_trace_abort(G(L));
1179
    }
1180
#endif
1181
    while (gcsteps-- > 0)
63,952✔
1182
      lj_gc_check(L);
541✔
1183
    return ret;
63,411✔
1184
  }
1185
  return -1;  /* Not a function. */
1186
}
1187

1188
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc