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