| 1 | /* |
| 2 | ** C type management. |
| 3 | ** Copyright (C) 2005-2021 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_strfmt.h" |
| 15 | #include "lj_ctype.h" |
| 16 | #include "lj_ccallback.h" |
| 17 | #include "lj_buf.h" |
| 18 | |
| 19 | /* -- C type definitions -------------------------------------------------- */ |
| 20 | |
| 21 | /* Predefined typedefs. */ |
| 22 | #define CTTDDEF(_) \ |
| 23 | /* Vararg handling. */ \ |
| 24 | _("va_list", P_VOID) \ |
| 25 | _("__builtin_va_list", P_VOID) \ |
| 26 | _("__gnuc_va_list", P_VOID) \ |
| 27 | /* From stddef.h. */ \ |
| 28 | _("ptrdiff_t", INT_PSZ) \ |
| 29 | _("size_t", UINT_PSZ) \ |
| 30 | _("wchar_t", WCHAR) \ |
| 31 | /* Subset of stdint.h. */ \ |
| 32 | _("int8_t", INT8) \ |
| 33 | _("int16_t", INT16) \ |
| 34 | _("int32_t", INT32) \ |
| 35 | _("int64_t", INT64) \ |
| 36 | _("uint8_t", UINT8) \ |
| 37 | _("uint16_t", UINT16) \ |
| 38 | _("uint32_t", UINT32) \ |
| 39 | _("uint64_t", UINT64) \ |
| 40 | _("intptr_t", INT_PSZ) \ |
| 41 | _("uintptr_t", UINT_PSZ) \ |
| 42 | /* From POSIX. */ \ |
| 43 | _("ssize_t", INT_PSZ) \ |
| 44 | /* End of typedef list. */ |
| 45 | |
| 46 | /* Keywords (only the ones we actually care for). */ |
| 47 | #define CTKWDEF(_) \ |
| 48 | /* Type specifiers. */ \ |
| 49 | _("void", -1, CTOK_VOID) \ |
| 50 | _("_Bool", 0, CTOK_BOOL) \ |
| 51 | _("bool", 1, CTOK_BOOL) \ |
| 52 | _("char", 1, CTOK_CHAR) \ |
| 53 | _("int", 4, CTOK_INT) \ |
| 54 | _("__int8", 1, CTOK_INT) \ |
| 55 | _("__int16", 2, CTOK_INT) \ |
| 56 | _("__int32", 4, CTOK_INT) \ |
| 57 | _("__int64", 8, CTOK_INT) \ |
| 58 | _("float", 4, CTOK_FP) \ |
| 59 | _("double", 8, CTOK_FP) \ |
| 60 | _("long", 0, CTOK_LONG) \ |
| 61 | _("short", 0, CTOK_SHORT) \ |
| 62 | _("_Complex", 0, CTOK_COMPLEX) \ |
| 63 | _("complex", 0, CTOK_COMPLEX) \ |
| 64 | _("__complex", 0, CTOK_COMPLEX) \ |
| 65 | _("__complex__", 0, CTOK_COMPLEX) \ |
| 66 | _("signed", 0, CTOK_SIGNED) \ |
| 67 | _("__signed", 0, CTOK_SIGNED) \ |
| 68 | _("__signed__", 0, CTOK_SIGNED) \ |
| 69 | _("unsigned", 0, CTOK_UNSIGNED) \ |
| 70 | /* Type qualifiers. */ \ |
| 71 | _("const", 0, CTOK_CONST) \ |
| 72 | _("__const", 0, CTOK_CONST) \ |
| 73 | _("__const__", 0, CTOK_CONST) \ |
| 74 | _("volatile", 0, CTOK_VOLATILE) \ |
| 75 | _("__volatile", 0, CTOK_VOLATILE) \ |
| 76 | _("__volatile__", 0, CTOK_VOLATILE) \ |
| 77 | _("restrict", 0, CTOK_RESTRICT) \ |
| 78 | _("__restrict", 0, CTOK_RESTRICT) \ |
| 79 | _("__restrict__", 0, CTOK_RESTRICT) \ |
| 80 | _("inline", 0, CTOK_INLINE) \ |
| 81 | _("__inline", 0, CTOK_INLINE) \ |
| 82 | _("__inline__", 0, CTOK_INLINE) \ |
| 83 | /* Storage class specifiers. */ \ |
| 84 | _("typedef", 0, CTOK_TYPEDEF) \ |
| 85 | _("extern", 0, CTOK_EXTERN) \ |
| 86 | _("static", 0, CTOK_STATIC) \ |
| 87 | _("auto", 0, CTOK_AUTO) \ |
| 88 | _("register", 0, CTOK_REGISTER) \ |
| 89 | /* GCC Attributes. */ \ |
| 90 | _("__extension__", 0, CTOK_EXTENSION) \ |
| 91 | _("__attribute", 0, CTOK_ATTRIBUTE) \ |
| 92 | _("__attribute__", 0, CTOK_ATTRIBUTE) \ |
| 93 | _("asm", 0, CTOK_ASM) \ |
| 94 | _("__asm", 0, CTOK_ASM) \ |
| 95 | _("__asm__", 0, CTOK_ASM) \ |
| 96 | /* MSVC Attributes. */ \ |
| 97 | _("__declspec", 0, CTOK_DECLSPEC) \ |
| 98 | _("__cdecl", CTCC_CDECL, CTOK_CCDECL) \ |
| 99 | _("__thiscall", CTCC_THISCALL, CTOK_CCDECL) \ |
| 100 | _("__fastcall", CTCC_FASTCALL, CTOK_CCDECL) \ |
| 101 | _("__stdcall", CTCC_STDCALL, CTOK_CCDECL) \ |
| 102 | _("__ptr32", 4, CTOK_PTRSZ) \ |
| 103 | _("__ptr64", 8, CTOK_PTRSZ) \ |
| 104 | /* Other type specifiers. */ \ |
| 105 | _("struct", 0, CTOK_STRUCT) \ |
| 106 | _("union", 0, CTOK_UNION) \ |
| 107 | _("enum", 0, CTOK_ENUM) \ |
| 108 | /* Operators. */ \ |
| 109 | _("sizeof", 0, CTOK_SIZEOF) \ |
| 110 | _("__alignof", 0, CTOK_ALIGNOF) \ |
| 111 | _("__alignof__", 0, CTOK_ALIGNOF) \ |
| 112 | /* End of keyword list. */ |
| 113 | |
| 114 | /* Type info for predefined types. Size merged in. */ |
| 115 | static CTInfo lj_ctype_typeinfo[] = { |
| 116 | #define CTTYINFODEF(id, sz, ct, info) CTINFO((ct),(((sz)&0x3fu)<<10)+(info)), |
| 117 | #define CTTDINFODEF(name, id) CTINFO(CT_TYPEDEF, CTID_##id), |
| 118 | #define CTKWINFODEF(name, sz, kw) CTINFO(CT_KW,(((sz)&0x3fu)<<10)+(kw)), |
| 119 | CTTYDEF(CTTYINFODEF) |
| 120 | CTTDDEF(CTTDINFODEF) |
| 121 | CTKWDEF(CTKWINFODEF) |
| 122 | #undef CTTYINFODEF |
| 123 | #undef CTTDINFODEF |
| 124 | #undef CTKWINFODEF |
| 125 | 0 |
| 126 | }; |
| 127 | |
| 128 | /* Predefined type names collected in a single string. */ |
| 129 | static const char * const lj_ctype_typenames = |
| 130 | #define CTTDNAMEDEF(name, id) name "\0" |
| 131 | #define CTKWNAMEDEF(name, sz, cds) name "\0" |
| 132 | CTTDDEF(CTTDNAMEDEF) |
| 133 | CTKWDEF(CTKWNAMEDEF) |
| 134 | #undef CTTDNAMEDEF |
| 135 | #undef CTKWNAMEDEF |
| 136 | ; |
| 137 | |
| 138 | #define CTTYPEINFO_NUM (sizeof(lj_ctype_typeinfo)/sizeof(CTInfo)-1) |
| 139 | #ifdef LUAJIT_CTYPE_CHECK_ANCHOR |
| 140 | #define CTTYPETAB_MIN CTTYPEINFO_NUM |
| 141 | #else |
| 142 | #define CTTYPETAB_MIN 128 |
| 143 | #endif |
| 144 | |
| 145 | /* -- C type interning ---------------------------------------------------- */ |
| 146 | |
| 147 | #define ct_hashtype(info, size) (hashrot(info, size) & CTHASH_MASK) |
| 148 | #define ct_hashname(name) \ |
| 149 | (hashrot(u32ptr(name), u32ptr(name) + HASH_BIAS) & CTHASH_MASK) |
| 150 | |
| 151 | /* Create new type element. */ |
| 152 | CTypeID lj_ctype_new(CTState *cts, CType **ctp) |
| 153 | { |
| 154 | CTypeID id = cts->top; |
| 155 | CType *ct; |
| 156 | lj_assertCTS(cts->L, "uninitialized cts->L" ); |
| 157 | if (LJ_UNLIKELY(id >= cts->sizetab)) { |
| 158 | if (id >= CTID_MAX) lj_err_msg(cts->L, LJ_ERR_TABOV); |
| 159 | #ifdef LUAJIT_CTYPE_CHECK_ANCHOR |
| 160 | ct = lj_mem_newvec(cts->L, id+1, CType); |
| 161 | memcpy(ct, cts->tab, id*sizeof(CType)); |
| 162 | memset(cts->tab, 0, id*sizeof(CType)); |
| 163 | lj_mem_freevec(cts->g, cts->tab, cts->sizetab, CType); |
| 164 | cts->tab = ct; |
| 165 | cts->sizetab = id+1; |
| 166 | #else |
| 167 | lj_mem_growvec(cts->L, cts->tab, cts->sizetab, CTID_MAX, CType); |
| 168 | #endif |
| 169 | } |
| 170 | cts->top = id+1; |
| 171 | *ctp = ct = &cts->tab[id]; |
| 172 | ct->info = 0; |
| 173 | ct->size = 0; |
| 174 | ct->sib = 0; |
| 175 | ct->next = 0; |
| 176 | setgcrefnull(ct->name); |
| 177 | return id; |
| 178 | } |
| 179 | |
| 180 | /* Intern a type element. */ |
| 181 | CTypeID lj_ctype_intern(CTState *cts, CTInfo info, CTSize size) |
| 182 | { |
| 183 | uint32_t h = ct_hashtype(info, size); |
| 184 | CTypeID id = cts->hash[h]; |
| 185 | lj_assertCTS(cts->L, "uninitialized cts->L" ); |
| 186 | while (id) { |
| 187 | CType *ct = ctype_get(cts, id); |
| 188 | if (ct->info == info && ct->size == size) |
| 189 | return id; |
| 190 | id = ct->next; |
| 191 | } |
| 192 | id = cts->top; |
| 193 | if (LJ_UNLIKELY(id >= cts->sizetab)) { |
| 194 | if (id >= CTID_MAX) lj_err_msg(cts->L, LJ_ERR_TABOV); |
| 195 | lj_mem_growvec(cts->L, cts->tab, cts->sizetab, CTID_MAX, CType); |
| 196 | } |
| 197 | cts->top = id+1; |
| 198 | cts->tab[id].info = info; |
| 199 | cts->tab[id].size = size; |
| 200 | cts->tab[id].sib = 0; |
| 201 | cts->tab[id].next = cts->hash[h]; |
| 202 | setgcrefnull(cts->tab[id].name); |
| 203 | cts->hash[h] = (CTypeID1)id; |
| 204 | return id; |
| 205 | } |
| 206 | |
| 207 | /* Add type element to hash table. */ |
| 208 | static void ctype_addtype(CTState *cts, CType *ct, CTypeID id) |
| 209 | { |
| 210 | uint32_t h = ct_hashtype(ct->info, ct->size); |
| 211 | ct->next = cts->hash[h]; |
| 212 | cts->hash[h] = (CTypeID1)id; |
| 213 | } |
| 214 | |
| 215 | /* Add named element to hash table. */ |
| 216 | void lj_ctype_addname(CTState *cts, CType *ct, CTypeID id) |
| 217 | { |
| 218 | uint32_t h = ct_hashname(gcref(ct->name)); |
| 219 | ct->next = cts->hash[h]; |
| 220 | cts->hash[h] = (CTypeID1)id; |
| 221 | } |
| 222 | |
| 223 | /* Get a C type by name, matching the type mask. */ |
| 224 | CTypeID lj_ctype_getname(CTState *cts, CType **ctp, GCstr *name, uint32_t tmask) |
| 225 | { |
| 226 | CTypeID id = cts->hash[ct_hashname(name)]; |
| 227 | while (id) { |
| 228 | CType *ct = ctype_get(cts, id); |
| 229 | if (gcref(ct->name) == obj2gco(name) && |
| 230 | ((tmask >> ctype_type(ct->info)) & 1)) { |
| 231 | *ctp = ct; |
| 232 | return id; |
| 233 | } |
| 234 | id = ct->next; |
| 235 | } |
| 236 | *ctp = &cts->tab[0]; /* Simplify caller logic. ctype_get() would assert. */ |
| 237 | return 0; |
| 238 | } |
| 239 | |
| 240 | /* Get a struct/union/enum/function field by name. */ |
| 241 | CType *lj_ctype_getfieldq(CTState *cts, CType *ct, GCstr *name, CTSize *ofs, |
| 242 | CTInfo *qual) |
| 243 | { |
| 244 | while (ct->sib) { |
| 245 | ct = ctype_get(cts, ct->sib); |
| 246 | if (gcref(ct->name) == obj2gco(name)) { |
| 247 | *ofs = ct->size; |
| 248 | return ct; |
| 249 | } |
| 250 | if (ctype_isxattrib(ct->info, CTA_SUBTYPE)) { |
| 251 | CType *fct, *cct = ctype_child(cts, ct); |
| 252 | CTInfo q = 0; |
| 253 | while (ctype_isattrib(cct->info)) { |
| 254 | if (ctype_attrib(cct->info) == CTA_QUAL) q |= cct->size; |
| 255 | cct = ctype_child(cts, cct); |
| 256 | } |
| 257 | fct = lj_ctype_getfieldq(cts, cct, name, ofs, qual); |
| 258 | if (fct) { |
| 259 | if (qual) *qual |= q; |
| 260 | *ofs += ct->size; |
| 261 | return fct; |
| 262 | } |
| 263 | } |
| 264 | } |
| 265 | return NULL; /* Not found. */ |
| 266 | } |
| 267 | |
| 268 | /* -- C type information -------------------------------------------------- */ |
| 269 | |
| 270 | /* Follow references and get raw type for a C type ID. */ |
| 271 | CType *lj_ctype_rawref(CTState *cts, CTypeID id) |
| 272 | { |
| 273 | CType *ct = ctype_get(cts, id); |
| 274 | while (ctype_isattrib(ct->info) || ctype_isref(ct->info)) |
| 275 | ct = ctype_child(cts, ct); |
| 276 | return ct; |
| 277 | } |
| 278 | |
| 279 | /* Get size for a C type ID. Does NOT support VLA/VLS. */ |
| 280 | CTSize lj_ctype_size(CTState *cts, CTypeID id) |
| 281 | { |
| 282 | CType *ct = ctype_raw(cts, id); |
| 283 | return ctype_hassize(ct->info) ? ct->size : CTSIZE_INVALID; |
| 284 | } |
| 285 | |
| 286 | /* Get size for a variable-length C type. Does NOT support other C types. */ |
| 287 | CTSize lj_ctype_vlsize(CTState *cts, CType *ct, CTSize nelem) |
| 288 | { |
| 289 | uint64_t xsz = 0; |
| 290 | if (ctype_isstruct(ct->info)) { |
| 291 | CTypeID arrid = 0, fid = ct->sib; |
| 292 | xsz = ct->size; /* Add the struct size. */ |
| 293 | while (fid) { |
| 294 | CType *ctf = ctype_get(cts, fid); |
| 295 | if (ctype_type(ctf->info) == CT_FIELD) |
| 296 | arrid = ctype_cid(ctf->info); /* Remember last field of VLS. */ |
| 297 | fid = ctf->sib; |
| 298 | } |
| 299 | ct = ctype_raw(cts, arrid); |
| 300 | } |
| 301 | lj_assertCTS(ctype_isvlarray(ct->info), "VLA expected" ); |
| 302 | ct = ctype_rawchild(cts, ct); /* Get array element. */ |
| 303 | lj_assertCTS(ctype_hassize(ct->info), "bad VLA without size" ); |
| 304 | /* Calculate actual size of VLA and check for overflow. */ |
| 305 | xsz += (uint64_t)ct->size * nelem; |
| 306 | return xsz < 0x80000000u ? (CTSize)xsz : CTSIZE_INVALID; |
| 307 | } |
| 308 | |
| 309 | /* Get type, qualifiers, size and alignment for a C type ID. */ |
| 310 | CTInfo lj_ctype_info(CTState *cts, CTypeID id, CTSize *szp) |
| 311 | { |
| 312 | CTInfo qual = 0; |
| 313 | CType *ct = ctype_get(cts, id); |
| 314 | for (;;) { |
| 315 | CTInfo info = ct->info; |
| 316 | if (ctype_isenum(info)) { |
| 317 | /* Follow child. Need to look at its attributes, too. */ |
| 318 | } else if (ctype_isattrib(info)) { |
| 319 | if (ctype_isxattrib(info, CTA_QUAL)) |
| 320 | qual |= ct->size; |
| 321 | else if (ctype_isxattrib(info, CTA_ALIGN) && !(qual & CTFP_ALIGNED)) |
| 322 | qual |= CTFP_ALIGNED + CTALIGN(ct->size); |
| 323 | } else { |
| 324 | if (!(qual & CTFP_ALIGNED)) qual |= (info & CTF_ALIGN); |
| 325 | qual |= (info & ~(CTF_ALIGN|CTMASK_CID)); |
| 326 | lj_assertCTS(ctype_hassize(info) || ctype_isfunc(info), |
| 327 | "ctype without size" ); |
| 328 | *szp = ctype_isfunc(info) ? CTSIZE_INVALID : ct->size; |
| 329 | break; |
| 330 | } |
| 331 | ct = ctype_get(cts, ctype_cid(info)); |
| 332 | } |
| 333 | return qual; |
| 334 | } |
| 335 | |
| 336 | /* Get ctype metamethod. */ |
| 337 | cTValue *lj_ctype_meta(CTState *cts, CTypeID id, MMS mm) |
| 338 | { |
| 339 | CType *ct = ctype_get(cts, id); |
| 340 | cTValue *tv; |
| 341 | while (ctype_isattrib(ct->info) || ctype_isref(ct->info)) { |
| 342 | id = ctype_cid(ct->info); |
| 343 | ct = ctype_get(cts, id); |
| 344 | } |
| 345 | if (ctype_isptr(ct->info) && |
| 346 | ctype_isfunc(ctype_get(cts, ctype_cid(ct->info))->info)) |
| 347 | tv = lj_tab_getstr(cts->miscmap, &cts->g->strempty); |
| 348 | else |
| 349 | tv = lj_tab_getinth(cts->miscmap, -(int32_t)id); |
| 350 | if (tv && tvistab(tv) && |
| 351 | (tv = lj_tab_getstr(tabV(tv), mmname_str(cts->g, mm))) && !tvisnil(tv)) |
| 352 | return tv; |
| 353 | return NULL; |
| 354 | } |
| 355 | |
| 356 | /* -- C type representation ----------------------------------------------- */ |
| 357 | |
| 358 | /* Fixed max. length of a C type representation. */ |
| 359 | #define CTREPR_MAX 512 |
| 360 | |
| 361 | typedef struct CTRepr { |
| 362 | char *pb, *pe; |
| 363 | CTState *cts; |
| 364 | lua_State *L; |
| 365 | int needsp; |
| 366 | int ok; |
| 367 | char buf[CTREPR_MAX]; |
| 368 | } CTRepr; |
| 369 | |
| 370 | /* Prepend string. */ |
| 371 | static void ctype_prepstr(CTRepr *ctr, const char *str, MSize len) |
| 372 | { |
| 373 | char *p = ctr->pb; |
| 374 | if (ctr->buf + len+1 > p) { ctr->ok = 0; return; } |
| 375 | if (ctr->needsp) *--p = ' '; |
| 376 | ctr->needsp = 1; |
| 377 | p -= len; |
| 378 | while (len-- > 0) p[len] = str[len]; |
| 379 | ctr->pb = p; |
| 380 | } |
| 381 | |
| 382 | #define ctype_preplit(ctr, str) ctype_prepstr((ctr), "" str, sizeof(str)-1) |
| 383 | |
| 384 | /* Prepend char. */ |
| 385 | static void ctype_prepc(CTRepr *ctr, int c) |
| 386 | { |
| 387 | if (ctr->buf >= ctr->pb) { ctr->ok = 0; return; } |
| 388 | *--ctr->pb = c; |
| 389 | } |
| 390 | |
| 391 | /* Prepend number. */ |
| 392 | static void ctype_prepnum(CTRepr *ctr, uint32_t n) |
| 393 | { |
| 394 | char *p = ctr->pb; |
| 395 | if (ctr->buf + 10+1 > p) { ctr->ok = 0; return; } |
| 396 | do { *--p = (char)('0' + n % 10); } while (n /= 10); |
| 397 | ctr->pb = p; |
| 398 | ctr->needsp = 0; |
| 399 | } |
| 400 | |
| 401 | /* Append char. */ |
| 402 | static void ctype_appc(CTRepr *ctr, int c) |
| 403 | { |
| 404 | if (ctr->pe >= ctr->buf + CTREPR_MAX) { ctr->ok = 0; return; } |
| 405 | *ctr->pe++ = c; |
| 406 | } |
| 407 | |
| 408 | /* Append number. */ |
| 409 | static void ctype_appnum(CTRepr *ctr, uint32_t n) |
| 410 | { |
| 411 | char buf[10]; |
| 412 | char *p = buf+sizeof(buf); |
| 413 | char *q = ctr->pe; |
| 414 | if (q > ctr->buf + CTREPR_MAX - 10) { ctr->ok = 0; return; } |
| 415 | do { *--p = (char)('0' + n % 10); } while (n /= 10); |
| 416 | do { *q++ = *p++; } while (p < buf+sizeof(buf)); |
| 417 | ctr->pe = q; |
| 418 | } |
| 419 | |
| 420 | /* Prepend qualifiers. */ |
| 421 | static void ctype_prepqual(CTRepr *ctr, CTInfo info) |
| 422 | { |
| 423 | if ((info & CTF_VOLATILE)) ctype_preplit(ctr, "volatile" ); |
| 424 | if ((info & CTF_CONST)) ctype_preplit(ctr, "const" ); |
| 425 | } |
| 426 | |
| 427 | /* Prepend named type. */ |
| 428 | static void ctype_preptype(CTRepr *ctr, CType *ct, CTInfo qual, const char *t) |
| 429 | { |
| 430 | if (gcref(ct->name)) { |
| 431 | GCstr *str = gco2str(gcref(ct->name)); |
| 432 | ctype_prepstr(ctr, strdata(str), str->len); |
| 433 | } else { |
| 434 | if (ctr->needsp) ctype_prepc(ctr, ' '); |
| 435 | ctype_prepnum(ctr, ctype_typeid(ctr->cts, ct)); |
| 436 | ctr->needsp = 1; |
| 437 | } |
| 438 | ctype_prepstr(ctr, t, (MSize)strlen(t)); |
| 439 | ctype_prepqual(ctr, qual); |
| 440 | } |
| 441 | |
| 442 | static void ctype_repr(CTRepr *ctr, CTypeID id) |
| 443 | { |
| 444 | CType *ct = ctype_get(ctr->cts, id); |
| 445 | CTInfo qual = 0; |
| 446 | int ptrto = 0; |
| 447 | for (;;) { |
| 448 | CTInfo info = ct->info; |
| 449 | CTSize size = ct->size; |
| 450 | switch (ctype_type(info)) { |
| 451 | case CT_NUM: |
| 452 | if ((info & CTF_BOOL)) { |
| 453 | ctype_preplit(ctr, "bool" ); |
| 454 | } else if ((info & CTF_FP)) { |
| 455 | if (size == sizeof(double)) ctype_preplit(ctr, "double" ); |
| 456 | else if (size == sizeof(float)) ctype_preplit(ctr, "float" ); |
| 457 | else ctype_preplit(ctr, "long double" ); |
| 458 | } else if (size == 1) { |
| 459 | if (!((info ^ CTF_UCHAR) & CTF_UNSIGNED)) ctype_preplit(ctr, "char" ); |
| 460 | else if (CTF_UCHAR) ctype_preplit(ctr, "signed char" ); |
| 461 | else ctype_preplit(ctr, "unsigned char" ); |
| 462 | } else if (size < 8) { |
| 463 | if (size == 4) ctype_preplit(ctr, "int" ); |
| 464 | else ctype_preplit(ctr, "short" ); |
| 465 | if ((info & CTF_UNSIGNED)) ctype_preplit(ctr, "unsigned" ); |
| 466 | } else { |
| 467 | ctype_preplit(ctr, "_t" ); |
| 468 | ctype_prepnum(ctr, size*8); |
| 469 | ctype_preplit(ctr, "int" ); |
| 470 | if ((info & CTF_UNSIGNED)) ctype_prepc(ctr, 'u'); |
| 471 | } |
| 472 | ctype_prepqual(ctr, (qual|info)); |
| 473 | return; |
| 474 | case CT_VOID: |
| 475 | ctype_preplit(ctr, "void" ); |
| 476 | ctype_prepqual(ctr, (qual|info)); |
| 477 | return; |
| 478 | case CT_STRUCT: |
| 479 | ctype_preptype(ctr, ct, qual, (info & CTF_UNION) ? "union" : "struct" ); |
| 480 | return; |
| 481 | case CT_ENUM: |
| 482 | if (id == CTID_CTYPEID) { |
| 483 | ctype_preplit(ctr, "ctype" ); |
| 484 | return; |
| 485 | } |
| 486 | ctype_preptype(ctr, ct, qual, "enum" ); |
| 487 | return; |
| 488 | case CT_ATTRIB: |
| 489 | if (ctype_attrib(info) == CTA_QUAL) qual |= size; |
| 490 | break; |
| 491 | case CT_PTR: |
| 492 | if ((info & CTF_REF)) { |
| 493 | ctype_prepc(ctr, '&'); |
| 494 | } else { |
| 495 | ctype_prepqual(ctr, (qual|info)); |
| 496 | if (LJ_64 && size == 4) ctype_preplit(ctr, "__ptr32" ); |
| 497 | ctype_prepc(ctr, '*'); |
| 498 | } |
| 499 | qual = 0; |
| 500 | ptrto = 1; |
| 501 | ctr->needsp = 1; |
| 502 | break; |
| 503 | case CT_ARRAY: |
| 504 | if (ctype_isrefarray(info)) { |
| 505 | ctr->needsp = 1; |
| 506 | if (ptrto) { ptrto = 0; ctype_prepc(ctr, '('); ctype_appc(ctr, ')'); } |
| 507 | ctype_appc(ctr, '['); |
| 508 | if (size != CTSIZE_INVALID) { |
| 509 | CTSize csize = ctype_child(ctr->cts, ct)->size; |
| 510 | ctype_appnum(ctr, csize ? size/csize : 0); |
| 511 | } else if ((info & CTF_VLA)) { |
| 512 | ctype_appc(ctr, '?'); |
| 513 | } |
| 514 | ctype_appc(ctr, ']'); |
| 515 | } else if ((info & CTF_COMPLEX)) { |
| 516 | if (size == 2*sizeof(float)) ctype_preplit(ctr, "float" ); |
| 517 | ctype_preplit(ctr, "complex" ); |
| 518 | return; |
| 519 | } else { |
| 520 | ctype_preplit(ctr, ")))" ); |
| 521 | ctype_prepnum(ctr, size); |
| 522 | ctype_preplit(ctr, "__attribute__((vector_size(" ); |
| 523 | } |
| 524 | break; |
| 525 | case CT_FUNC: |
| 526 | ctr->needsp = 1; |
| 527 | if (ptrto) { ptrto = 0; ctype_prepc(ctr, '('); ctype_appc(ctr, ')'); } |
| 528 | ctype_appc(ctr, '('); |
| 529 | ctype_appc(ctr, ')'); |
| 530 | break; |
| 531 | default: |
| 532 | lj_assertG_(ctr->cts->g, 0, "bad ctype %08x" , info); |
| 533 | break; |
| 534 | } |
| 535 | ct = ctype_get(ctr->cts, ctype_cid(info)); |
| 536 | } |
| 537 | } |
| 538 | |
| 539 | /* Return a printable representation of a C type. */ |
| 540 | GCstr *lj_ctype_repr(lua_State *L, CTypeID id, GCstr *name) |
| 541 | { |
| 542 | global_State *g = G(L); |
| 543 | CTRepr ctr; |
| 544 | ctr.pb = ctr.pe = &ctr.buf[CTREPR_MAX/2]; |
| 545 | ctr.cts = ctype_ctsG(g); |
| 546 | ctr.L = L; |
| 547 | ctr.ok = 1; |
| 548 | ctr.needsp = 0; |
| 549 | if (name) ctype_prepstr(&ctr, strdata(name), name->len); |
| 550 | ctype_repr(&ctr, id); |
| 551 | if (LJ_UNLIKELY(!ctr.ok)) return lj_str_newlit(L, "?" ); |
| 552 | return lj_str_new(L, ctr.pb, ctr.pe - ctr.pb); |
| 553 | } |
| 554 | |
| 555 | /* Convert int64_t/uint64_t to string with 'LL' or 'ULL' suffix. */ |
| 556 | GCstr *lj_ctype_repr_int64(lua_State *L, uint64_t n, int isunsigned) |
| 557 | { |
| 558 | char buf[1+20+3]; |
| 559 | char *p = buf+sizeof(buf); |
| 560 | int sign = 0; |
| 561 | *--p = 'L'; *--p = 'L'; |
| 562 | if (isunsigned) { |
| 563 | *--p = 'U'; |
| 564 | } else if ((int64_t)n < 0) { |
| 565 | n = (uint64_t)-(int64_t)n; |
| 566 | sign = 1; |
| 567 | } |
| 568 | do { *--p = (char)('0' + n % 10); } while (n /= 10); |
| 569 | if (sign) *--p = '-'; |
| 570 | return lj_str_new(L, p, (size_t)(buf+sizeof(buf)-p)); |
| 571 | } |
| 572 | |
| 573 | /* Convert complex to string with 'i' or 'I' suffix. */ |
| 574 | GCstr *lj_ctype_repr_complex(lua_State *L, void *sp, CTSize size) |
| 575 | { |
| 576 | SBuf *sb = lj_buf_tmp_(L); |
| 577 | TValue re, im; |
| 578 | if (size == 2*sizeof(double)) { |
| 579 | re.n = *(double *)sp; im.n = ((double *)sp)[1]; |
| 580 | } else { |
| 581 | re.n = (double)*(float *)sp; im.n = (double)((float *)sp)[1]; |
| 582 | } |
| 583 | lj_strfmt_putfnum(sb, STRFMT_G14, re.n); |
| 584 | if (!(im.u32.hi & 0x80000000u) || im.n != im.n) lj_buf_putchar(sb, '+'); |
| 585 | lj_strfmt_putfnum(sb, STRFMT_G14, im.n); |
| 586 | lj_buf_putchar(sb, sbufP(sb)[-1] >= 'a' ? 'I' : 'i'); |
| 587 | return lj_buf_str(L, sb); |
| 588 | } |
| 589 | |
| 590 | /* -- C type state -------------------------------------------------------- */ |
| 591 | |
| 592 | /* Initialize C type table and state. */ |
| 593 | CTState *lj_ctype_init(lua_State *L) |
| 594 | { |
| 595 | CTState *cts = lj_mem_newt(L, sizeof(CTState), CTState); |
| 596 | CType *ct = lj_mem_newvec(L, CTTYPETAB_MIN, CType); |
| 597 | const char *name = lj_ctype_typenames; |
| 598 | CTypeID id; |
| 599 | memset(cts, 0, sizeof(CTState)); |
| 600 | cts->tab = ct; |
| 601 | cts->sizetab = CTTYPETAB_MIN; |
| 602 | cts->top = CTTYPEINFO_NUM; |
| 603 | cts->L = NULL; |
| 604 | cts->g = G(L); |
| 605 | for (id = 0; id < CTTYPEINFO_NUM; id++, ct++) { |
| 606 | CTInfo info = lj_ctype_typeinfo[id]; |
| 607 | ct->size = (CTSize)((int32_t)(info << 16) >> 26); |
| 608 | ct->info = info & 0xffff03ffu; |
| 609 | ct->sib = 0; |
| 610 | if (ctype_type(info) == CT_KW || ctype_istypedef(info)) { |
| 611 | size_t len = strlen(name); |
| 612 | GCstr *str = lj_str_new(L, name, len); |
| 613 | ctype_setname(ct, str); |
| 614 | name += len+1; |
| 615 | lj_ctype_addname(cts, ct, id); |
| 616 | } else { |
| 617 | setgcrefnull(ct->name); |
| 618 | ct->next = 0; |
| 619 | if (!ctype_isenum(info)) ctype_addtype(cts, ct, id); |
| 620 | } |
| 621 | } |
| 622 | setmref(G(L)->ctype_state, cts); |
| 623 | return cts; |
| 624 | } |
| 625 | |
| 626 | /* Free C type table and state. */ |
| 627 | void lj_ctype_freestate(global_State *g) |
| 628 | { |
| 629 | CTState *cts = ctype_ctsG(g); |
| 630 | if (cts) { |
| 631 | lj_ccallback_mcode_free(cts); |
| 632 | lj_mem_freevec(g, cts->tab, cts->sizetab, CType); |
| 633 | lj_mem_freevec(g, cts->cb.cbid, cts->cb.sizeid, CTypeID1); |
| 634 | lj_mem_freet(g, cts); |
| 635 | } |
| 636 | } |
| 637 | |
| 638 | #endif |
| 639 | |