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

tarantool / luajit / 5784751762

07 Aug 2023 11:54AM UTC coverage: 84.282% (-3.1%) from 87.373%
5784751762

push

github

ligurio
setup-gcovr [TO SQUASH]

5157 of 6002 branches covered (85.92%)

Branch coverage included in aggregate %.

19632 of 23410 relevant lines covered (83.86%)

229380.51 hits per line

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

77.68
/src/lj_cdata.c
1
/*
2
** C data management.
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

17
/* -- C data allocation --------------------------------------------------- */
18

19
/* Allocate a new C data object holding a reference to another object. */
20
GCcdata *lj_cdata_newref(CTState *cts, const void *p, CTypeID id)
1,898✔
21
{
22
  CTypeID refid = lj_ctype_intern(cts, CTINFO_REF(id), CTSIZE_PTR);
1,898✔
23
  GCcdata *cd = lj_cdata_new(cts, refid, CTSIZE_PTR);
1,898✔
24
  *(const void **)cdataptr(cd) = p;
1,898✔
25
  return cd;
1,898✔
26
}
27

28
/* Allocate variable-sized or specially aligned C data object. */
29
GCcdata *lj_cdata_newv(lua_State *L, CTypeID id, CTSize sz, CTSize align)
2,340✔
30
{
31
  global_State *g;
2,340✔
32
  MSize extra = sizeof(GCcdataVar) + sizeof(GCcdata) +
2,340✔
33
                (align > CT_MEMALIGN ? (1u<<align) - (1u<<CT_MEMALIGN) : 0);
×
34
  char *p = lj_mem_newt(L, extra + sz, char);
2,340✔
35
  uintptr_t adata = (uintptr_t)p + sizeof(GCcdataVar) + sizeof(GCcdata);
2,340✔
36
  uintptr_t almask = (1u << align) - 1u;
2,340✔
37
  GCcdata *cd = (GCcdata *)(((adata + almask) & ~almask) - sizeof(GCcdata));
2,340✔
38
  lua_assert((char *)cd - p < 65536);
2,340✔
39
  cdatav(cd)->offset = (uint16_t)((char *)cd - p);
2,340✔
40
  cdatav(cd)->extra = extra;
2,340✔
41
  cdatav(cd)->len = sz;
2,340✔
42
  g = G(L);
2,340✔
43
  setgcrefr(cd->nextgc, g->gc.root);
2,340✔
44
  setgcref(g->gc.root, obj2gco(cd));
2,340✔
45
  newwhite(g, obj2gco(cd));
2,340✔
46
  cd->marked |= 0x80;
2,340✔
47
  cd->gct = ~LJ_TCDATA;
2,340✔
48
  cd->ctypeid = id;
2,340✔
49
  g->gc.cdatanum++;
2,340✔
50
  return cd;
2,340✔
51
}
52

53
/* Allocate arbitrary C data object. */
54
GCcdata *lj_cdata_newx(CTState *cts, CTypeID id, CTSize sz, CTInfo info)
1,941✔
55
{
56
  if (!(info & CTF_VLA) && ctype_align(info) <= CT_MEMALIGN)
1,941✔
57
    return lj_cdata_new(cts, id, sz);
1,487✔
58
  else
59
    return lj_cdata_newv(cts->L, id, sz, ctype_align(info));
454✔
60
}
61

62
/* Free a C data object. */
63
void LJ_FASTCALL lj_cdata_free(global_State *g, GCcdata *cd)
15,661✔
64
{
65
  if (LJ_UNLIKELY(cd->marked & LJ_GC_CDATA_FIN)) {
15,661✔
66
    GCobj *root;
2✔
67
    makewhite(g, obj2gco(cd));
2✔
68
    markfinalized(obj2gco(cd));
2✔
69
    if ((root = gcref(g->gc.mmudata)) != NULL) {
2✔
70
      setgcrefr(cd->nextgc, root->gch.nextgc);
×
71
      setgcref(root->gch.nextgc, obj2gco(cd));
×
72
      setgcref(g->gc.mmudata, obj2gco(cd));
×
73
    } else {
74
      setgcref(cd->nextgc, obj2gco(cd));
2✔
75
      setgcref(g->gc.mmudata, obj2gco(cd));
2✔
76
    }
77
  } else if (LJ_LIKELY(!cdataisv(cd))) {
15,659✔
78
    CType *ct = ctype_raw(ctype_ctsG(g), cd->ctypeid);
13,319✔
79
    CTSize sz = ctype_hassize(ct->info) ? ct->size : CTSIZE_PTR;
13,319✔
80
    lua_assert(ctype_hassize(ct->info) || ctype_isfunc(ct->info) ||
13,319✔
81
               ctype_isextern(ct->info));
82
    lj_mem_free(g, cd, sizeof(GCcdata) + sz);
13,319✔
83
    g->gc.cdatanum--;
13,319✔
84
  } else {
85
    lj_mem_free(g, memcdatav(cd), sizecdatav(cd));
2,340✔
86
    g->gc.cdatanum--;
2,340✔
87
  }
88
}
15,661✔
89

90
void lj_cdata_setfin(lua_State *L, GCcdata *cd, GCobj *obj, uint32_t it)
2✔
91
{
92
  GCtab *t = ctype_ctsG(G(L))->finalizer;
2✔
93
  if (gcref(t->metatable)) {
2✔
94
    /* Add cdata to finalizer table, if still enabled. */
95
    TValue *tv, tmp;
2✔
96
    setcdataV(L, &tmp, cd);
2✔
97
    lj_gc_anybarriert(L, t);
2✔
98
    tv = lj_tab_set(L, t, &tmp);
2✔
99
    if (it == LJ_TNIL) {
2✔
100
      setnilV(tv);
×
101
      cd->marked &= ~LJ_GC_CDATA_FIN;
×
102
    } else {
103
      setgcV(L, tv, obj, it);
2✔
104
      cd->marked |= LJ_GC_CDATA_FIN;
2✔
105
    }
106
  }
107
}
2✔
108

109
/* -- C data indexing ----------------------------------------------------- */
110

111
/* Index C data by a TValue. Return CType and pointer. */
112
CType *lj_cdata_index(CTState *cts, GCcdata *cd, cTValue *key, uint8_t **pp,
16,951✔
113
                      CTInfo *qual)
114
{
115
  uint8_t *p = (uint8_t *)cdataptr(cd);
16,951✔
116
  CType *ct = ctype_get(cts, cd->ctypeid);
16,951✔
117
  ptrdiff_t idx;
16,951✔
118

119
  /* Resolve reference for cdata object. */
120
  if (ctype_isref(ct->info)) {
16,951✔
121
    lua_assert(ct->size == CTSIZE_PTR);
1,846✔
122
    p = *(uint8_t **)p;
1,846✔
123
    ct = ctype_child(cts, ct);
1,846✔
124
  }
125

126
collect_attrib:
15,105✔
127
  /* Skip attributes and collect qualifiers. */
128
  while (ctype_isattrib(ct->info)) {
17,414✔
129
    if (ctype_attrib(ct->info) == CTA_QUAL) *qual |= ct->size;
×
130
    ct = ctype_child(cts, ct);
×
131
  }
132
  lua_assert(!ctype_isref(ct->info));  /* Interning rejects refs to refs. */
17,414✔
133

134
  if (tvisint(key)) {
17,414✔
135
    idx = (ptrdiff_t)intV(key);
136
    goto integer_key;
137
  } else if (tvisnum(key)) {  /* Numeric key. */
17,414✔
138
#ifdef _MSC_VER
139
    /* Workaround for MSVC bug. */
140
    volatile
141
#endif
142
    lua_Number n = numV(key);
9,714✔
143
    idx = LJ_64 ? (ptrdiff_t)n : (ptrdiff_t)lj_num2int(n);
9,714✔
144
  integer_key:
9,858✔
145
    if (ctype_ispointer(ct->info)) {
9,858✔
146
      CTSize sz = lj_ctype_size(cts, ctype_cid(ct->info));  /* Element size. */
9,858✔
147
      if (sz == CTSIZE_INVALID)
9,858✔
148
        lj_err_caller(cts->L, LJ_ERR_FFI_INVSIZE);
×
149
      if (ctype_isptr(ct->info)) {
9,858✔
150
        p = (uint8_t *)cdata_getptr(p, ct->size);
720✔
151
      } else if ((ct->info & (CTF_VECTOR|CTF_COMPLEX))) {
9,138✔
152
        if ((ct->info & CTF_COMPLEX)) idx &= 1;
174✔
153
        *qual |= CTF_CONST;  /* Valarray elements are constant. */
174✔
154
      }
155
      *pp = p + idx*(int32_t)sz;
9,858✔
156
      return ct;
9,858✔
157
    }
158
  } else if (tviscdata(key)) {  /* Integer cdata key. */
7,700✔
159
    GCcdata *cdk = cdataV(key);
144✔
160
    CType *ctk = ctype_raw(cts, cdk->ctypeid);
144✔
161
    if (ctype_isenum(ctk->info)) ctk = ctype_child(cts, ctk);
144✔
162
    if (ctype_isinteger(ctk->info)) {
144✔
163
      lj_cconv_ct_ct(cts, ctype_get(cts, CTID_INT_PSZ), ctk,
144✔
164
                     (uint8_t *)&idx, cdataptr(cdk), 0);
144✔
165
      goto integer_key;
144✔
166
    }
167
  } else if (tvisstr(key)) {  /* String key. */
7,556✔
168
    GCstr *name = strV(key);
7,556✔
169
    if (ctype_isstruct(ct->info)) {
7,556✔
170
      CTSize ofs;
6,098✔
171
      CType *fct = lj_ctype_getfieldq(cts, ct, name, &ofs, qual);
6,098✔
172
      if (fct) {
6,098✔
173
        *pp = p + ofs;
6,098✔
174
        return fct;
6,098✔
175
      }
176
    } else if (ctype_iscomplex(ct->info)) {
1,458✔
177
      if (name->len == 2) {
994✔
178
        *qual |= CTF_CONST;  /* Complex fields are constant. */
994✔
179
        if (strdata(name)[0] == 'r' && strdata(name)[1] == 'e') {
994✔
180
          *pp = p;
526✔
181
          return ct;
526✔
182
        } else if (strdata(name)[0] == 'i' && strdata(name)[1] == 'm') {
468✔
183
          *pp = p + (ct->size >> 1);
468✔
184
          return ct;
468✔
185
        }
186
      }
187
    } else if (cd->ctypeid == CTID_CTYPEID) {
464✔
188
      /* Allow indexing a (pointer to) struct constructor to get constants. */
189
      CType *sct = ctype_raw(cts, *(CTypeID *)p);
×
190
      if (ctype_isptr(sct->info))
×
191
        sct = ctype_rawchild(cts, sct);
×
192
      if (ctype_isstruct(sct->info)) {
×
193
        CTSize ofs;
×
194
        CType *fct = lj_ctype_getfield(cts, sct, name, &ofs);
×
195
        if (fct && ctype_isconstval(fct->info))
×
196
          return fct;
×
197
      }
198
      ct = sct;  /* Allow resolving metamethods for constructors, too. */
199
    }
200
  }
201
  if (ctype_isptr(ct->info)) {  /* Automatically perform '->'. */
464✔
202
    if (ctype_isstruct(ctype_rawchild(cts, ct)->info)) {
463✔
203
      p = (uint8_t *)cdata_getptr(p, ct->size);
463✔
204
      ct = ctype_child(cts, ct);
463✔
205
      goto collect_attrib;
463✔
206
    }
207
  }
208
  *qual |= 1;  /* Lookup failed. */
1✔
209
  return ct;  /* But return the resolved raw type. */
1✔
210
}
211

212
/* -- C data getters ------------------------------------------------------ */
213

214
/* Get constant value and convert to TValue. */
215
static void cdata_getconst(CTState *cts, TValue *o, CType *ct)
×
216
{
217
  CType *ctt = ctype_child(cts, ct);
×
218
  lua_assert(ctype_isinteger(ctt->info) && ctt->size <= 4);
×
219
  /* Constants are already zero-extended/sign-extended to 32 bits. */
220
  if ((ctt->info & CTF_UNSIGNED) && (int32_t)ct->size < 0)
×
221
    setnumV(o, (lua_Number)(uint32_t)ct->size);
×
222
  else
223
    setintV(o, (int32_t)ct->size);
×
224
}
225

226
/* Get C data value and convert to TValue. */
227
int lj_cdata_get(CTState *cts, CType *s, TValue *o, uint8_t *sp)
11,453✔
228
{
229
  CTypeID sid;
11,453✔
230

231
  if (ctype_isconstval(s->info)) {
11,453✔
232
    cdata_getconst(cts, o, s);
×
233
    return 0;  /* No GC step needed. */
×
234
  } else if (ctype_isbitfield(s->info)) {
11,453✔
235
    return lj_cconv_tv_bf(cts, s, o, sp);
×
236
  }
237

238
  /* Get child type of pointer/array/field. */
239
  lua_assert(ctype_ispointer(s->info) || ctype_isfield(s->info));
11,453✔
240
  sid = ctype_cid(s->info);
11,453✔
241
  s = ctype_get(cts, sid);
11,453✔
242

243
  /* Resolve reference for field. */
244
  if (ctype_isref(s->info)) {
11,453✔
245
    lua_assert(s->size == CTSIZE_PTR);
×
246
    sp = *(uint8_t **)sp;
×
247
    sid = ctype_cid(s->info);
×
248
    s = ctype_get(cts, sid);
×
249
  }
250

251
  /* Skip attributes. */
252
  while (ctype_isattrib(s->info))
11,453✔
253
    s = ctype_child(cts, s);
×
254

255
  return lj_cconv_tv_ct(cts, s, sid, o, sp);
11,453✔
256
}
257

258
/* -- C data setters ------------------------------------------------------ */
259

260
/* Convert TValue and set C data value. */
261
void lj_cdata_set(CTState *cts, CType *d, uint8_t *dp, TValue *o, CTInfo qual)
5,497✔
262
{
263
  if (ctype_isconstval(d->info)) {
5,497✔
264
    goto err_const;
×
265
  } else if (ctype_isbitfield(d->info)) {
5,497✔
266
    if (((d->info|qual) & CTF_CONST)) goto err_const;
×
267
    lj_cconv_bf_tv(cts, d, dp, o);
×
268
    return;
×
269
  }
270

271
  /* Get child type of pointer/array/field. */
272
  lua_assert(ctype_ispointer(d->info) || ctype_isfield(d->info));
5,497✔
273
  d = ctype_child(cts, d);
5,497✔
274

275
  /* Resolve reference for field. */
276
  if (ctype_isref(d->info)) {
5,497✔
277
    lua_assert(d->size == CTSIZE_PTR);
×
278
    dp = *(uint8_t **)dp;
×
279
    d = ctype_child(cts, d);
×
280
  }
281

282
  /* Skip attributes and collect qualifiers. */
283
  for (;;) {
×
284
    if (ctype_isattrib(d->info)) {
5,497✔
285
      if (ctype_attrib(d->info) == CTA_QUAL) qual |= d->size;
×
286
    } else {
287
      break;
288
    }
289
    d = ctype_child(cts, d);
×
290
  }
291

292
  lua_assert(ctype_hassize(d->info) && !ctype_isvoid(d->info));
5,497✔
293

294
  if (((d->info|qual) & CTF_CONST)) {
5,497✔
295
  err_const:
×
296
    lj_err_caller(cts->L, LJ_ERR_FFI_WRCONST);
×
297
  }
298

299
  lj_cconv_ct_tv(cts, d, dp, o, 0);
5,497✔
300
}
301

302
#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

© 2026 Coveralls, Inc