• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/ucode/lib/ffi/uc_cdata.c

  1 /*
  2 ** C data management.
  3 ** Copyright (C) 2005-2025 Mike Pall. See Copyright Notice below.
  4 **
  5 ** This file contains derived work from LuaJIT's FFI C data objects (lj_cdata.c).
  6 **
  7 ** Modifications:
  8 ** - Adapted VM interactions to use ucode's API (uc_vm_t, uc_value_t, etc.)
  9 ** - Adapted C data allocation to use ucode resource system (uc_cdata_new, etc.)
 10 ** - Removed JIT-specific code and dependencies
 11 **
 12 ** See NOTICE and ATTRIBUTION.md for complete attribution details.
 13 */
 14 
 15 
 16 #include "uc_ctype.h"
 17 #include "uc_cconv.h"
 18 #include "uc_cdata.h"
 19 
 20 /* -- C data allocation --------------------------------------------------- */
 21 
 22 /* Allocate a new C data object holding a reference to another object. */
 23 uc_value_t *uc_cdata_newref(uc_vm_t *vm, const void *p, CTypeID id)
 24 {
 25         CTypeID refid = uc_ctype_intern(ctype_cts(vm), CTINFO_REF(id), CTSIZE_PTR);
 26         uc_value_t *res = uc_cdata_new(vm, refid, CTSIZE_PTR);
 27 
 28         *(const void **)uc_cdata_dataptr(res) = p;
 29 
 30         return res;
 31 }
 32 
 33 /* Allocate variable-sized or specially aligned C data object. */
 34 uc_value_t *uc_cdata_newv(uc_vm_t *vm, CTypeID id, CTSize sz, CTSize align)
 35 {
 36         // global_State *g;
 37         // FIXME: non-power-of-two alignments?
 38         if (align < 1) align = 1;  // Ensure minimum alignment
 39         size_t hdrsize = (sizeof(uc_resource_t) + align - 1) & -align;
 40         size_t extra = sizeof(GCcdataVar) + sizeof(GCcdata)
 41             + (align > CT_MEMALIGN ? (1u << align) - (1u << CT_MEMALIGN) : 0);
 42 
 43         uc_resource_t *res = xalloc(hdrsize + sz + extra);
 44         res->header.type = UC_RESOURCE;
 45         res->header.refcount = 1;
 46         res->type = ucv_resource_type_lookup(vm, "ffi.ctype");
 47 
 48         char *p = (char *)res + hdrsize;
 49         uintptr_t adata = (uintptr_t)p + sizeof(GCcdataVar) + sizeof(GCcdata);
 50         uintptr_t almask = (1u << align) - 1u;
 51         GCcdata *cd = (GCcdata *)(((adata + almask) & ~almask) - sizeof(GCcdata));
 52         cdatav(cd)->offset = (uint16_t)((char *)cd - p);
 53         cdatav(cd)->extra = extra;
 54         cdatav(cd)->len = sz;
 55         cd->ctypeid = id;
 56         cd->isvla = 1;
 57         cd->refs = NULL;
 58 
 59         res->data = cd;
 60 
 61         return &res->header;
 62 }
 63 
 64 /* Allocate arbitrary C data object. */
 65 uc_value_t *uc_cdata_newx(uc_vm_t *vm, CTypeID id, CTSize sz, CTInfo info)
 66 {
 67         if (!(info & CTF_VLA) && ctype_align(info) <= CT_MEMALIGN)
 68                 return uc_cdata_new(vm, id, sz);
 69         else
 70                 return uc_cdata_newv(vm, id, sz, ctype_align(info));
 71 }
 72 
 73 /* -- C data indexing ----------------------------------------------------- */
 74 
 75 /* Index C data by a TValue. Return CType and pointer. */
 76 CType *uc_cdata_index(CTState *cts, GCcdata *cd, uc_value_t *key, uint8_t **pp,
 77                                           CTInfo *qual)
 78 {
 79         uint8_t *p = (uint8_t *)cdataptr(cd);
 80         CType *ct = ctype_get(cts, cd->ctypeid);
 81         ptrdiff_t idx;
 82         uc_type_t ut = ucv_type(key);
 83         GCcdata *cdk = (ut == UC_RESOURCE) ? ucv_resource_data(key, "ffi.ctype") : NULL;
 84 
 85         /* Skip extern and attribute wrappers */
 86         while (ctype_isextern(ct->info) || ctype_isattrib(ct->info))
 87                 ct = ctype_child(cts, ct);
 88 
 89         /* Resolve reference for cdata object. */
 90         if (ctype_isref(ct->info))
 91         {
 92                 uc_assertCTS(ct->size == CTSIZE_PTR, "ref is not pointer-sized");
 93                 p = *(uint8_t **)p;
 94                 ct = ctype_child(cts, ct);
 95         }
 96 
 97 collect_attrib:
 98         /* Skip any remaining attributes and collect qualifiers. */
 99         while (ctype_isattrib(ct->info))
100         {
101                 if (ctype_attrib(ct->info) == CTA_QUAL)
102                         *qual |= ct->size;
103                 ct = ctype_child(cts, ct);
104         }
105         /* Interning rejects refs to refs. */
106         uc_assertCTS(!ctype_isref(ct->info), "bad ref of ref");
107 
108         if (ut == UC_INTEGER)
109         {
110                 idx = (ptrdiff_t)ucv_int64_get(key);
111                 goto integer_key;
112         }
113         else if (ut == UC_DOUBLE)
114         { /* Numeric key. */
115                 double d = ucv_double_get(key);
116                 idx = UC_64 ? (ptrdiff_t)d : (ptrdiff_t)uc_num2int(d);
117         integer_key:
118                 if (ctype_ispointer(ct->info) || ctype_isrefarray(ct->info))
119                 {
120                         CTSize sz = uc_ctype_size(cts, ctype_cid(ct->info)); /* Element size. */
121                         if (sz == CTSIZE_INVALID) {
122                                 uc_vm_raise_exception(cts->vm, EXCEPTION_TYPE,
123                                         "size of C type is unknown or too large");
124 
125                                 return NULL;
126                         }
127                         if (ctype_isptr(ct->info))
128                         {
129                                 p = (uint8_t *)cdata_getptr(p, ct->size);
130                         }
131                         else if ((ct->info & (CTF_VECTOR | CTF_COMPLEX)))
132                         {
133                                 if ((ct->info & CTF_COMPLEX))
134                                         idx &= 1;
135                                 *qual |= CTF_CONST; /* Valarray elements are constant. */
136                         }
137                         *pp = p + idx * (int32_t)sz;
138                         return ct;
139                 }
140         }
141         else if (cdk)
142         { /* Integer cdata key. */
143                 CType *ctk = ctype_raw(cts, cdk->ctypeid);
144                 if (ctype_isenum(ctk->info))
145                         ctk = ctype_child(cts, ctk);
146                 if (ctype_isinteger(ctk->info))
147                 {
148                         uc_cconv_ct_ct(cts, ctype_get(cts, CTID_INT_PSZ), ctk,
149                                                    (uint8_t *)&idx, cdataptr(cdk), 0);
150                         goto integer_key;
151                 }
152         }
153         else if (ut == UC_STRING)
154         { /* String key. */
155                 if (ctype_isstruct(ct->info))
156                 {
157                         CTSize ofs;
158                         CType *fct = uc_ctype_getfieldq(cts, ct, key, &ofs, qual);
159                         if (fct)
160                         {
161                                 *pp = p + ofs;
162                                 return fct;
163                         }
164                 }
165                 else if (ctype_iscomplex(ct->info))
166                 {
167                         if (ucv_string_length(key) == 2)
168                         {
169                                 char *name = ucv_string_get(key);
170 
171                                 *qual |= CTF_CONST; /* Complex fields are constant. */
172                                 if (name[0] == 'r' && name[1] == 'e')
173                                 {
174                                         *pp = p;
175                                         return ct;
176                                 }
177                                 else if (name[0] == 'i' && name[1] == 'm')
178                                 {
179                                         *pp = p + (ct->size >> 1);
180                                         return ct;
181                                 }
182                         }
183                 }
184                 else if (cd->ctypeid == CTID_CTYPEID)
185                 {
186                         /* Allow indexing a (pointer to) struct constructor to get constants. */
187                         CType *sct = ctype_raw(cts, *(CTypeID *)p);
188                         if (ctype_isptr(sct->info))
189                                 sct = ctype_rawchild(cts, sct);
190                         if (ctype_isstruct(sct->info))
191                         {
192                                 CTSize ofs;
193                                 CType *fct = uc_ctype_getfield(cts, sct, key, &ofs);
194                                 if (fct && ctype_isconstval(fct->info))
195                                         return fct;
196                         }
197                         ct = sct; /* Allow resolving metamethods for constructors, too. */
198                 }
199         }
200         if (ctype_isptr(ct->info))
201         { /* Automatically perform '->'. */
202                 if (ctype_isstruct(ctype_rawchild(cts, ct)->info))
203                 {
204                         p = (uint8_t *)cdata_getptr(p, ct->size);
205                         ct = ctype_child(cts, ct);
206                         goto collect_attrib;
207                 }
208         }
209         *qual |= 1; /* Lookup failed. */
210         return ct;      /* But return the resolved raw type. */
211 }
212 
213 /* -- C data getters ------------------------------------------------------ */
214 
215 /* Get constant value and convert to TValue. */
216 static void cdata_getconst(CTState *cts, uc_value_t **uv, CType *ct)
217 {
218         CType *ctt = ctype_child(cts, ct);
219         uc_assertCTS(ctype_isinteger(ctt->info) && ctt->size <= 4,
220                                  "only 32 bit const supported"); /* NYI */
221 
222         ucv_put(*uv);
223 
224         /* Constants are already zero-extended/sign-extended to 32 bits. */
225         if ((ctt->info & CTF_UNSIGNED) && (int32_t)ct->size < 0)
226                 *uv = ucv_int64_new((int64_t)(uint32_t)ct->size);
227         else
228                 *uv = ucv_int64_new((int64_t)(int32_t)ct->size);
229 }
230 
231 /* Get C data value and convert to TValue. */
232 int uc_cdata_get(CTState *cts, CType *s, uc_value_t **uv, uint8_t *sp)
233 {
234         CTypeID sid;
235 
236         if (ctype_isconstval(s->info))
237         {
238                 cdata_getconst(cts, uv, s);
239                 return 0; /* No GC step needed. */
240         }
241         else if (ctype_isbitfield(s->info))
242         {
243                 return uc_cconv_tv_bf(cts, s, uv, sp);
244         }
245 
246         /* Get child type of pointer/array/field. */
247         uc_assertCTS(ctype_ispointer(s->info) || ctype_isfield(s->info),
248                                  "pointer or field expected");
249         sid = ctype_cid(s->info);
250         s = ctype_get(cts, sid);
251 
252         /* Resolve reference for field. */
253         if (ctype_isref(s->info))
254         {
255                 uc_assertCTS(s->size == CTSIZE_PTR, "ref is not pointer-sized");
256                 sp = *(uint8_t **)sp;
257                 sid = ctype_cid(s->info);
258                 s = ctype_get(cts, sid);
259         }
260 
261         /* Skip attributes. */
262         while (ctype_isattrib(s->info))
263                 s = ctype_child(cts, s);
264 
265         return uc_cconv_tv_ct(cts, s, sid, uv, sp);
266 }
267 
268 /* -- C data setters ------------------------------------------------------ */
269 
270 /* Convert TValue and set C data value. */
271 void uc_cdata_set(CTState *cts, CType *d, uint8_t *dp, uc_value_t *uv, CTInfo qual, uc_value_t **refs)
272 {
273         if (ctype_isconstval(d->info))
274         {
275                 goto err_const;
276         }
277         else if (ctype_isbitfield(d->info))
278         {
279                 if (((d->info | qual) & CTF_CONST))
280                         goto err_const;
281                 uc_cconv_bf_tv(cts, d, dp, uv, refs);
282                 return;
283         }
284 
285         /* Get child type of pointer/array/field. */
286         uc_assertCTS(ctype_ispointer(d->info) || ctype_isfield(d->info),
287                                  "pointer or field expected");
288         d = ctype_child(cts, d);
289 
290         /* Resolve reference for field. */
291         if (ctype_isref(d->info))
292         {
293                 uc_assertCTS(d->size == CTSIZE_PTR, "ref is not pointer-sized");
294                 dp = *(uint8_t **)dp;
295                 d = ctype_child(cts, d);
296         }
297 
298         /* Skip attributes and collect qualifiers. */
299         for (;;)
300         {
301                 if (ctype_isattrib(d->info))
302                 {
303                         if (ctype_attrib(d->info) == CTA_QUAL)
304                                 qual |= d->size;
305                 }
306                 else
307                 {
308                         break;
309                 }
310                 d = ctype_child(cts, d);
311         }
312 
313         uc_assertCTS(ctype_hassize(d->info), "store to ctype without size");
314         uc_assertCTS(!ctype_isvoid(d->info), "store to void type");
315 
316         if (((d->info | qual) & CTF_CONST))
317         {
318         err_const:
319                 uc_vm_raise_exception(cts->vm, EXCEPTION_REFERENCE,
320                         "attempt to write to constant location");
321 
322                 return;
323         }
324 
325         uc_cconv_ct_tv(cts, d, dp, uv, 0, refs);
326 }
327 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt