src/lj_cdata.c - luajit-2.0-src

Functions defined

Source code

  1. /*
  2. ** C data management.
  3. ** Copyright (C) 2005-2015 Mike Pall. See Copyright Notice in luajit.h
  4. */

  5. #include "lj_obj.h"

  6. #if LJ_HASFFI

  7. #include "lj_gc.h"
  8. #include "lj_err.h"
  9. #include "lj_tab.h"
  10. #include "lj_ctype.h"
  11. #include "lj_cconv.h"
  12. #include "lj_cdata.h"

  13. /* -- C data allocation --------------------------------------------------- */

  14. /* Allocate a new C data object holding a reference to another object. */
  15. GCcdata *lj_cdata_newref(CTState *cts, const void *p, CTypeID id)
  16. {
  17.   CTypeID refid = lj_ctype_intern(cts, CTINFO_REF(id), CTSIZE_PTR);
  18.   GCcdata *cd = lj_cdata_new(cts, refid, CTSIZE_PTR);
  19.   *(const void **)cdataptr(cd) = p;
  20.   return cd;
  21. }

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

  45. /* Free a C data object. */
  46. void LJ_FASTCALL lj_cdata_free(global_State *g, GCcdata *cd)
  47. {
  48.   if (LJ_UNLIKELY(cd->marked & LJ_GC_CDATA_FIN)) {
  49.     GCobj *root;
  50.     makewhite(g, obj2gco(cd));
  51.     markfinalized(obj2gco(cd));
  52.     if ((root = gcref(g->gc.mmudata)) != NULL) {
  53.       setgcrefr(cd->nextgc, root->gch.nextgc);
  54.       setgcref(root->gch.nextgc, obj2gco(cd));
  55.       setgcref(g->gc.mmudata, obj2gco(cd));
  56.     } else {
  57.       setgcref(cd->nextgc, obj2gco(cd));
  58.       setgcref(g->gc.mmudata, obj2gco(cd));
  59.     }
  60.   } else if (LJ_LIKELY(!cdataisv(cd))) {
  61.     CType *ct = ctype_raw(ctype_ctsG(g), cd->ctypeid);
  62.     CTSize sz = ctype_hassize(ct->info) ? ct->size : CTSIZE_PTR;
  63.     lua_assert(ctype_hassize(ct->info) || ctype_isfunc(ct->info) ||
  64.                ctype_isextern(ct->info));
  65.     lj_mem_free(g, cd, sizeof(GCcdata) + sz);
  66.   } else {
  67.     lj_mem_free(g, memcdatav(cd), sizecdatav(cd));
  68.   }
  69. }

  70. void lj_cdata_setfin(lua_State *L, GCcdata *cd, GCobj *obj, uint32_t it)
  71. {
  72.   GCtab *t = ctype_ctsG(G(L))->finalizer;
  73.   if (gcref(t->metatable)) {
  74.     /* Add cdata to finalizer table, if still enabled. */
  75.     TValue *tv, tmp;
  76.     setcdataV(L, &tmp, cd);
  77.     lj_gc_anybarriert(L, t);
  78.     tv = lj_tab_set(L, t, &tmp);
  79.     setgcV(L, tv, obj, it);
  80.     if (!tvisnil(tv))
  81.       cd->marked |= LJ_GC_CDATA_FIN;
  82.     else
  83.       cd->marked &= ~LJ_GC_CDATA_FIN;
  84.   }
  85. }

  86. /* -- C data indexing ----------------------------------------------------- */

  87. /* Index C data by a TValue. Return CType and pointer. */
  88. CType *lj_cdata_index(CTState *cts, GCcdata *cd, cTValue *key, uint8_t **pp,
  89.                       CTInfo *qual)
  90. {
  91.   uint8_t *p = (uint8_t *)cdataptr(cd);
  92.   CType *ct = ctype_get(cts, cd->ctypeid);
  93.   ptrdiff_t idx;

  94.   /* Resolve reference for cdata object. */
  95.   if (ctype_isref(ct->info)) {
  96.     lua_assert(ct->size == CTSIZE_PTR);
  97.     p = *(uint8_t **)p;
  98.     ct = ctype_child(cts, ct);
  99.   }

  100. collect_attrib:
  101.   /* Skip attributes and collect qualifiers. */
  102.   while (ctype_isattrib(ct->info)) {
  103.     if (ctype_attrib(ct->info) == CTA_QUAL) *qual |= ct->size;
  104.     ct = ctype_child(cts, ct);
  105.   }
  106.   lua_assert(!ctype_isref(ct->info));  /* Interning rejects refs to refs. */

  107.   if (tvisint(key)) {
  108.     idx = (ptrdiff_t)intV(key);
  109.     goto integer_key;
  110.   } else if (tvisnum(key)) {  /* Numeric key. */
  111.     idx = LJ_64 ? (ptrdiff_t)numV(key) : (ptrdiff_t)lj_num2int(numV(key));
  112.   integer_key:
  113.     if (ctype_ispointer(ct->info)) {
  114.       CTSize sz = lj_ctype_size(cts, ctype_cid(ct->info));  /* Element size. */
  115.       if (sz == CTSIZE_INVALID)
  116.         lj_err_caller(cts->L, LJ_ERR_FFI_INVSIZE);
  117.       if (ctype_isptr(ct->info)) {
  118.         p = (uint8_t *)cdata_getptr(p, ct->size);
  119.       } else if ((ct->info & (CTF_VECTOR|CTF_COMPLEX))) {
  120.         if ((ct->info & CTF_COMPLEX)) idx &= 1;
  121.         *qual |= CTF_CONST/* Valarray elements are constant. */
  122.       }
  123.       *pp = p + idx*(int32_t)sz;
  124.       return ct;
  125.     }
  126.   } else if (tviscdata(key)) {  /* Integer cdata key. */
  127.     GCcdata *cdk = cdataV(key);
  128.     CType *ctk = ctype_raw(cts, cdk->ctypeid);
  129.     if (ctype_isenum(ctk->info)) ctk = ctype_child(cts, ctk);
  130.     if (ctype_isinteger(ctk->info)) {
  131.       lj_cconv_ct_ct(cts, ctype_get(cts, CTID_INT_PSZ), ctk,
  132.                      (uint8_t *)&idx, cdataptr(cdk), 0);
  133.       goto integer_key;
  134.     }
  135.   } else if (tvisstr(key)) {  /* String key. */
  136.     GCstr *name = strV(key);
  137.     if (ctype_isstruct(ct->info)) {
  138.       CTSize ofs;
  139.       CType *fct = lj_ctype_getfieldq(cts, ct, name, &ofs, qual);
  140.       if (fct) {
  141.         *pp = p + ofs;
  142.         return fct;
  143.       }
  144.     } else if (ctype_iscomplex(ct->info)) {
  145.       if (name->len == 2) {
  146.         *qual |= CTF_CONST/* Complex fields are constant. */
  147.         if (strdata(name)[0] == 'r' && strdata(name)[1] == 'e') {
  148.           *pp = p;
  149.           return ct;
  150.         } else if (strdata(name)[0] == 'i' && strdata(name)[1] == 'm') {
  151.           *pp = p + (ct->size >> 1);
  152.           return ct;
  153.         }
  154.       }
  155.     } else if (cd->ctypeid == CTID_CTYPEID) {
  156.       /* Allow indexing a (pointer to) struct constructor to get constants. */
  157.       CType *sct = ctype_raw(cts, *(CTypeID *)p);
  158.       if (ctype_isptr(sct->info))
  159.         sct = ctype_rawchild(cts, sct);
  160.       if (ctype_isstruct(sct->info)) {
  161.         CTSize ofs;
  162.         CType *fct = lj_ctype_getfield(cts, sct, name, &ofs);
  163.         if (fct && ctype_isconstval(fct->info))
  164.           return fct;
  165.       }
  166.       ct = sct;  /* Allow resolving metamethods for constructors, too. */
  167.     }
  168.   }
  169.   if (ctype_isptr(ct->info)) {  /* Automatically perform '->'. */
  170.     if (ctype_isstruct(ctype_rawchild(cts, ct)->info)) {
  171.       p = (uint8_t *)cdata_getptr(p, ct->size);
  172.       ct = ctype_child(cts, ct);
  173.       goto collect_attrib;
  174.     }
  175.   }
  176.   *qual |= 1/* Lookup failed. */
  177.   return ct;  /* But return the resolved raw type. */
  178. }

  179. /* -- C data getters ------------------------------------------------------ */

  180. /* Get constant value and convert to TValue. */
  181. static void cdata_getconst(CTState *cts, TValue *o, CType *ct)
  182. {
  183.   CType *ctt = ctype_child(cts, ct);
  184.   lua_assert(ctype_isinteger(ctt->info) && ctt->size <= 4);
  185.   /* Constants are already zero-extended/sign-extended to 32 bits. */
  186.   if ((ctt->info & CTF_UNSIGNED) && (int32_t)ct->size < 0)
  187.     setnumV(o, (lua_Number)(uint32_t)ct->size);
  188.   else
  189.     setintV(o, (int32_t)ct->size);
  190. }

  191. /* Get C data value and convert to TValue. */
  192. int lj_cdata_get(CTState *cts, CType *s, TValue *o, uint8_t *sp)
  193. {
  194.   CTypeID sid;

  195.   if (ctype_isconstval(s->info)) {
  196.     cdata_getconst(cts, o, s);
  197.     return 0/* No GC step needed. */
  198.   } else if (ctype_isbitfield(s->info)) {
  199.     return lj_cconv_tv_bf(cts, s, o, sp);
  200.   }

  201.   /* Get child type of pointer/array/field. */
  202.   lua_assert(ctype_ispointer(s->info) || ctype_isfield(s->info));
  203.   sid = ctype_cid(s->info);
  204.   s = ctype_get(cts, sid);

  205.   /* Resolve reference for field. */
  206.   if (ctype_isref(s->info)) {
  207.     lua_assert(s->size == CTSIZE_PTR);
  208.     sp = *(uint8_t **)sp;
  209.     sid = ctype_cid(s->info);
  210.     s = ctype_get(cts, sid);
  211.   }

  212.   /* Skip attributes. */
  213.   while (ctype_isattrib(s->info))
  214.     s = ctype_child(cts, s);

  215.   return lj_cconv_tv_ct(cts, s, sid, o, sp);
  216. }

  217. /* -- C data setters ------------------------------------------------------ */

  218. /* Convert TValue and set C data value. */
  219. void lj_cdata_set(CTState *cts, CType *d, uint8_t *dp, TValue *o, CTInfo qual)
  220. {
  221.   if (ctype_isconstval(d->info)) {
  222.     goto err_const;
  223.   } else if (ctype_isbitfield(d->info)) {
  224.     if (((d->info|qual) & CTF_CONST)) goto err_const;
  225.     lj_cconv_bf_tv(cts, d, dp, o);
  226.     return;
  227.   }

  228.   /* Get child type of pointer/array/field. */
  229.   lua_assert(ctype_ispointer(d->info) || ctype_isfield(d->info));
  230.   d = ctype_child(cts, d);

  231.   /* Resolve reference for field. */
  232.   if (ctype_isref(d->info)) {
  233.     lua_assert(d->size == CTSIZE_PTR);
  234.     dp = *(uint8_t **)dp;
  235.     d = ctype_child(cts, d);
  236.   }

  237.   /* Skip attributes and collect qualifiers. */
  238.   for (;;) {
  239.     if (ctype_isattrib(d->info)) {
  240.       if (ctype_attrib(d->info) == CTA_QUAL) qual |= d->size;
  241.     } else {
  242.       break;
  243.     }
  244.     d = ctype_child(cts, d);
  245.   }

  246.   lua_assert(ctype_hassize(d->info) && !ctype_isvoid(d->info));

  247.   if (((d->info|qual) & CTF_CONST)) {
  248.   err_const:
  249.     lj_err_caller(cts->L, LJ_ERR_FFI_WRCONST);
  250.   }

  251.   lj_cconv_ct_tv(cts, d, dp, o, 0);
  252. }

  253. #endif