root/lj_cdata.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. lj_cdata_newref
  2. lj_cdata_newv
  3. lj_cdata_free
  4. lj_cdata_setfin
  5. lj_cdata_index
  6. cdata_getconst
  7. lj_cdata_get
  8. lj_cdata_set

   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_str.h"
  13 #include "lj_tab.h"
  14 #include "lj_ctype.h"
  15 #include "lj_cconv.h"
  16 #include "lj_cdata.h"
  17 
  18 /* -- C data allocation --------------------------------------------------- */
  19 
  20 /* Allocate a new C data object holding a reference to another object. */
  21 GCcdata *lj_cdata_newref(CTState *cts, const void *p, CTypeID id)
  22 {
  23   CTypeID refid = lj_ctype_intern(cts, CTINFO_REF(id), CTSIZE_PTR);
  24   GCcdata *cd = lj_cdata_new(cts, refid, CTSIZE_PTR);
  25   *(const void **)cdataptr(cd) = p;
  26   return cd;
  27 }
  28 
  29 /* Allocate variable-sized or specially aligned C data object. */
  30 GCcdata *lj_cdata_newv(CTState *cts, CTypeID id, CTSize sz, CTSize align)
  31 {
  32   global_State *g;
  33   MSize extra = sizeof(GCcdataVar) + sizeof(GCcdata) +
  34                 (align > CT_MEMALIGN ? (1u<<align) - (1u<<CT_MEMALIGN) : 0);
  35   char *p = lj_mem_newt(cts->L, extra + sz, char);
  36   uintptr_t adata = (uintptr_t)p + sizeof(GCcdataVar) + sizeof(GCcdata);
  37   uintptr_t almask = (1u << align) - 1u;
  38   GCcdata *cd = (GCcdata *)(((adata + almask) & ~almask) - sizeof(GCcdata));
  39   lua_assert((char *)cd - p < 65536);
  40   cdatav(cd)->offset = (uint16_t)((char *)cd - p);
  41   cdatav(cd)->extra = extra;
  42   cdatav(cd)->len = sz;
  43   g = cts->g;
  44   setgcrefr(cd->nextgc, g->gc.root);
  45   setgcref(g->gc.root, obj2gco(cd));
  46   newwhite(g, obj2gco(cd));
  47   cd->marked |= 0x80;
  48   cd->gct = ~LJ_TCDATA;
  49   cd->ctypeid = id;
  50   return cd;
  51 }
  52 
  53 /* Free a C data object. */
  54 void LJ_FASTCALL lj_cdata_free(global_State *g, GCcdata *cd)
  55 {
  56   if (LJ_UNLIKELY(cd->marked & LJ_GC_CDATA_FIN)) {
  57     GCobj *root;
  58     makewhite(g, obj2gco(cd));
  59     markfinalized(obj2gco(cd));
  60     if ((root = gcref(g->gc.mmudata)) != NULL) {
  61       setgcrefr(cd->nextgc, root->gch.nextgc);
  62       setgcref(root->gch.nextgc, obj2gco(cd));
  63       setgcref(g->gc.mmudata, obj2gco(cd));
  64     } else {
  65       setgcref(cd->nextgc, obj2gco(cd));
  66       setgcref(g->gc.mmudata, obj2gco(cd));
  67     }
  68   } else if (LJ_LIKELY(!cdataisv(cd))) {
  69     CType *ct = ctype_raw(ctype_ctsG(g), cd->ctypeid);
  70     CTSize sz = ctype_hassize(ct->info) ? ct->size : CTSIZE_PTR;
  71     lua_assert(ctype_hassize(ct->info) || ctype_isfunc(ct->info) ||
  72                ctype_isextern(ct->info));
  73     lj_mem_free(g, cd, sizeof(GCcdata) + sz);
  74   } else {
  75     lj_mem_free(g, memcdatav(cd), sizecdatav(cd));
  76   }
  77 }
  78 
  79 TValue * LJ_FASTCALL lj_cdata_setfin(lua_State *L, GCcdata *cd)
  80 {
  81   global_State *g = G(L);
  82   GCtab *t = ctype_ctsG(g)->finalizer;
  83   if (gcref(t->metatable)) {
  84     /* Add cdata to finalizer table, if still enabled. */
  85     TValue *tv, tmp;
  86     setcdataV(L, &tmp, cd);
  87     lj_gc_anybarriert(L, t);
  88     tv = lj_tab_set(L, t, &tmp);
  89     cd->marked |= LJ_GC_CDATA_FIN;
  90     return tv;
  91   } else {
  92     /* Otherwise return dummy TValue. */
  93     return &g->tmptv;
  94   }
  95 }
  96 
  97 /* -- C data indexing ----------------------------------------------------- */
  98 
  99 /* Index C data by a TValue. Return CType and pointer. */
 100 CType *lj_cdata_index(CTState *cts, GCcdata *cd, cTValue *key, uint8_t **pp,
 101                       CTInfo *qual)
 102 {
 103   uint8_t *p = (uint8_t *)cdataptr(cd);
 104   CType *ct = ctype_get(cts, cd->ctypeid);
 105   ptrdiff_t idx;
 106 
 107   /* Resolve reference for cdata object. */
 108   if (ctype_isref(ct->info)) {
 109     lua_assert(ct->size == CTSIZE_PTR);
 110     p = *(uint8_t **)p;
 111     ct = ctype_child(cts, ct);
 112   }
 113 
 114 collect_attrib:
 115   /* Skip attributes and collect qualifiers. */
 116   while (ctype_isattrib(ct->info)) {
 117     if (ctype_attrib(ct->info) == CTA_QUAL) *qual |= ct->size;
 118     ct = ctype_child(cts, ct);
 119   }
 120   lua_assert(!ctype_isref(ct->info));  /* Interning rejects refs to refs. */
 121 
 122   if (tvisint(key)) {
 123     idx = (ptrdiff_t)intV(key);
 124     goto integer_key;
 125   } else if (tvisnum(key)) {  /* Numeric key. */
 126     idx = LJ_64 ? (ptrdiff_t)numV(key) : (ptrdiff_t)lj_num2int(numV(key));
 127   integer_key:
 128     if (ctype_ispointer(ct->info)) {
 129       CTSize sz = lj_ctype_size(cts, ctype_cid(ct->info));  /* Element size. */
 130       if (sz == CTSIZE_INVALID)
 131         lj_err_caller(cts->L, LJ_ERR_FFI_INVSIZE);
 132       if (ctype_isptr(ct->info)) {
 133         p = (uint8_t *)cdata_getptr(p, ct->size);
 134       } else if ((ct->info & (CTF_VECTOR|CTF_COMPLEX))) {
 135         if ((ct->info & CTF_COMPLEX)) idx &= 1;
 136         *qual |= CTF_CONST;  /* Valarray elements are constant. */
 137       }
 138       *pp = p + idx*(int32_t)sz;
 139       return ct;
 140     }
 141   } else if (tviscdata(key)) {  /* Integer cdata key. */
 142     GCcdata *cdk = cdataV(key);
 143     CType *ctk = ctype_raw(cts, cdk->ctypeid);
 144     if (ctype_isenum(ctk->info)) ctk = ctype_child(cts, ctk);
 145     if (ctype_isinteger(ctk->info)) {
 146       lj_cconv_ct_ct(cts, ctype_get(cts, CTID_INT_PSZ), ctk,
 147                      (uint8_t *)&idx, cdataptr(cdk), 0);
 148       goto integer_key;
 149     }
 150   } else if (tvisstr(key)) {  /* String key. */
 151     GCstr *name = strV(key);
 152     if (ctype_isstruct(ct->info)) {
 153       CTSize ofs;
 154       CType *fct = lj_ctype_getfieldq(cts, ct, name, &ofs, qual);
 155       if (fct) {
 156         *pp = p + ofs;
 157         return fct;
 158       }
 159     } else if (ctype_iscomplex(ct->info)) {
 160       if (name->len == 2) {
 161         *qual |= CTF_CONST;  /* Complex fields are constant. */
 162         if (strdata(name)[0] == 'r' && strdata(name)[1] == 'e') {
 163           *pp = p;
 164           return ct;
 165         } else if (strdata(name)[0] == 'i' && strdata(name)[1] == 'm') {
 166           *pp = p + (ct->size >> 1);
 167           return ct;
 168         }
 169       }
 170     } else if (cd->ctypeid == CTID_CTYPEID) {
 171       /* Allow indexing a (pointer to) struct constructor to get constants. */
 172       CType *sct = ctype_raw(cts, *(CTypeID *)p);
 173       if (ctype_isptr(sct->info))
 174         sct = ctype_rawchild(cts, sct);
 175       if (ctype_isstruct(sct->info)) {
 176         CTSize ofs;
 177         CType *fct = lj_ctype_getfield(cts, sct, name, &ofs);
 178         if (fct && ctype_isconstval(fct->info))
 179           return fct;
 180       }
 181       ct = sct;  /* Allow resolving metamethods for constructors, too. */
 182     }
 183   }
 184   if (ctype_isptr(ct->info)) {  /* Automatically perform '->'. */
 185     if (ctype_isstruct(ctype_rawchild(cts, ct)->info)) {
 186       p = (uint8_t *)cdata_getptr(p, ct->size);
 187       ct = ctype_child(cts, ct);
 188       goto collect_attrib;
 189     }
 190   }
 191   *qual |= 1;  /* Lookup failed. */
 192   return ct;  /* But return the resolved raw type. */
 193 }
 194 
 195 /* -- C data getters ------------------------------------------------------ */
 196 
 197 /* Get constant value and convert to TValue. */
 198 static void cdata_getconst(CTState *cts, TValue *o, CType *ct)
 199 {
 200   CType *ctt = ctype_child(cts, ct);
 201   lua_assert(ctype_isinteger(ctt->info) && ctt->size <= 4);
 202   /* Constants are already zero-extended/sign-extended to 32 bits. */
 203   if ((ctt->info & CTF_UNSIGNED) && (int32_t)ct->size < 0)
 204     setnumV(o, (lua_Number)(uint32_t)ct->size);
 205   else
 206     setintV(o, (int32_t)ct->size);
 207 }
 208 
 209 /* Get C data value and convert to TValue. */
 210 int lj_cdata_get(CTState *cts, CType *s, TValue *o, uint8_t *sp)
 211 {
 212   CTypeID sid;
 213 
 214   if (ctype_isconstval(s->info)) {
 215     cdata_getconst(cts, o, s);
 216     return 0;  /* No GC step needed. */
 217   } else if (ctype_isbitfield(s->info)) {
 218     return lj_cconv_tv_bf(cts, s, o, sp);
 219   }
 220 
 221   /* Get child type of pointer/array/field. */
 222   lua_assert(ctype_ispointer(s->info) || ctype_isfield(s->info));
 223   sid = ctype_cid(s->info);
 224   s = ctype_get(cts, sid);
 225 
 226   /* Resolve reference for field. */
 227   if (ctype_isref(s->info)) {
 228     lua_assert(s->size == CTSIZE_PTR);
 229     sp = *(uint8_t **)sp;
 230     sid = ctype_cid(s->info);
 231     s = ctype_get(cts, sid);
 232   }
 233 
 234   /* Skip attributes. */
 235   while (ctype_isattrib(s->info))
 236     s = ctype_child(cts, s);
 237 
 238   return lj_cconv_tv_ct(cts, s, sid, o, sp);
 239 }
 240 
 241 /* -- C data setters ------------------------------------------------------ */
 242 
 243 /* Convert TValue and set C data value. */
 244 void lj_cdata_set(CTState *cts, CType *d, uint8_t *dp, TValue *o, CTInfo qual)
 245 {
 246   if (ctype_isconstval(d->info)) {
 247     goto err_const;
 248   } else if (ctype_isbitfield(d->info)) {
 249     if (((d->info|qual) & CTF_CONST)) goto err_const;
 250     lj_cconv_bf_tv(cts, d, dp, o);
 251     return;
 252   }
 253 
 254   /* Get child type of pointer/array/field. */
 255   lua_assert(ctype_ispointer(d->info) || ctype_isfield(d->info));
 256   d = ctype_child(cts, d);
 257 
 258   /* Resolve reference for field. */
 259   if (ctype_isref(d->info)) {
 260     lua_assert(d->size == CTSIZE_PTR);
 261     dp = *(uint8_t **)dp;
 262     d = ctype_child(cts, d);
 263   }
 264 
 265   /* Skip attributes and collect qualifiers. */
 266   for (;;) {
 267     if (ctype_isattrib(d->info)) {
 268       if (ctype_attrib(d->info) == CTA_QUAL) qual |= d->size;
 269     } else {
 270       break;
 271     }
 272     d = ctype_child(cts, d);
 273   }
 274 
 275   lua_assert(ctype_hassize(d->info) && !ctype_isvoid(d->info));
 276 
 277   if (((d->info|qual) & CTF_CONST)) {
 278   err_const:
 279     lj_err_caller(cts->L, LJ_ERR_FFI_WRCONST);
 280   }
 281 
 282   lj_cconv_ct_tv(cts, d, dp, o, 0);
 283 }
 284 
 285 #endif

/* [<][>][^][v][top][bottom][index][help] */