ljx

FORK: LuaJIT with native 5.2 and 5.3 support
git clone https://git.neptards.moe/neptards/ljx.git
Log | Files | Refs | README

lj_cdata.c (9053B)


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