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 | |