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