3 ** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
17 /* -- C data allocation --------------------------------------------------- */
19 /* Allocate a new C data object holding a reference to another object. */
20 GCcdata
*lj_cdata_newref(CTState
*cts
, const void *p
, CTypeID id
)
22 CTypeID refid
= lj_ctype_intern(cts
, CTINFO_REF(id
), CTSIZE_PTR
);
23 GCcdata
*cd
= lj_cdata_new(cts
, refid
, CTSIZE_PTR
);
24 *(const void **)cdataptr(cd
) = p
;
28 /* Allocate variable-sized or specially aligned C data object. */
29 GCcdata
*lj_cdata_newv(lua_State
*L
, CTypeID id
, CTSize sz
, CTSize align
)
32 MSize extra
= sizeof(GCcdataVar
) + sizeof(GCcdata
) +
33 (align
> CT_MEMALIGN
? (1u<<align
) - (1u<<CT_MEMALIGN
) : 0);
34 char *p
= lj_mem_newt(L
, extra
+ sz
, char);
35 uintptr_t adata
= (uintptr_t)p
+ sizeof(GCcdataVar
) + sizeof(GCcdata
);
36 uintptr_t almask
= (1u << align
) - 1u;
37 GCcdata
*cd
= (GCcdata
*)(((adata
+ almask
) & ~almask
) - sizeof(GCcdata
));
38 lj_assertL((char *)cd
- p
< 65536, "excessive cdata alignment");
39 cdatav(cd
)->offset
= (uint16_t)((char *)cd
- p
);
40 cdatav(cd
)->extra
= extra
;
43 setgcrefr(cd
->nextgc
, g
->gc
.root
);
44 setgcref(g
->gc
.root
, obj2gco(cd
));
45 newwhite(g
, obj2gco(cd
));
52 /* Allocate arbitrary C data object. */
53 GCcdata
*lj_cdata_newx(CTState
*cts
, CTypeID id
, CTSize sz
, CTInfo info
)
55 if (!(info
& CTF_VLA
) && ctype_align(info
) <= CT_MEMALIGN
)
56 return lj_cdata_new(cts
, id
, sz
);
58 return lj_cdata_newv(cts
->L
, id
, sz
, ctype_align(info
));
61 /* Free a C data object. */
62 void LJ_FASTCALL
lj_cdata_free(global_State
*g
, GCcdata
*cd
)
64 if (LJ_UNLIKELY(cd
->marked
& LJ_GC_CDATA_FIN
)) {
66 makewhite(g
, obj2gco(cd
));
67 markfinalized(obj2gco(cd
));
68 if ((root
= gcref(g
->gc
.mmudata
)) != NULL
) {
69 setgcrefr(cd
->nextgc
, root
->gch
.nextgc
);
70 setgcref(root
->gch
.nextgc
, obj2gco(cd
));
71 setgcref(g
->gc
.mmudata
, obj2gco(cd
));
73 setgcref(cd
->nextgc
, obj2gco(cd
));
74 setgcref(g
->gc
.mmudata
, obj2gco(cd
));
76 } else if (LJ_LIKELY(!cdataisv(cd
))) {
77 CType
*ct
= ctype_raw(ctype_ctsG(g
), cd
->ctypeid
);
78 CTSize sz
= ctype_hassize(ct
->info
) ? ct
->size
: CTSIZE_PTR
;
79 lj_assertG(ctype_hassize(ct
->info
) || ctype_isfunc(ct
->info
) ||
80 ctype_isextern(ct
->info
), "free of ctype without a size");
81 lj_mem_free(g
, cd
, sizeof(GCcdata
) + sz
);
83 lj_mem_free(g
, memcdatav(cd
), sizecdatav(cd
));
87 void lj_cdata_setfin(lua_State
*L
, GCcdata
*cd
, GCobj
*obj
, uint32_t it
)
89 GCtab
*t
= ctype_ctsG(G(L
))->finalizer
;
90 if (gcref(t
->metatable
)) {
91 /* Add cdata to finalizer table, if still enabled. */
93 setcdataV(L
, &tmp
, cd
);
94 lj_gc_anybarriert(L
, t
);
95 tv
= lj_tab_set(L
, t
, &tmp
);
98 cd
->marked
&= ~LJ_GC_CDATA_FIN
;
100 setgcV(L
, tv
, obj
, it
);
101 cd
->marked
|= LJ_GC_CDATA_FIN
;
106 /* -- C data indexing ----------------------------------------------------- */
108 /* Index C data by a TValue. Return CType and pointer. */
109 CType
*lj_cdata_index(CTState
*cts
, GCcdata
*cd
, cTValue
*key
, uint8_t **pp
,
112 uint8_t *p
= (uint8_t *)cdataptr(cd
);
113 CType
*ct
= ctype_get(cts
, cd
->ctypeid
);
116 /* Resolve reference for cdata object. */
117 if (ctype_isref(ct
->info
)) {
118 lj_assertCTS(ct
->size
== CTSIZE_PTR
, "ref is not pointer-sized");
120 ct
= ctype_child(cts
, ct
);
124 /* Skip attributes and collect qualifiers. */
125 while (ctype_isattrib(ct
->info
)) {
126 if (ctype_attrib(ct
->info
) == CTA_QUAL
) *qual
|= ct
->size
;
127 ct
= ctype_child(cts
, ct
);
129 /* Interning rejects refs to refs. */
130 lj_assertCTS(!ctype_isref(ct
->info
), "bad ref of ref");
133 idx
= (ptrdiff_t)intV(key
);
135 } else if (tvisnum(key
)) { /* Numeric key. */
137 /* Workaround for MSVC bug. */
140 lua_Number n
= numV(key
);
141 idx
= LJ_64
? (ptrdiff_t)n
: (ptrdiff_t)lj_num2int(n
);
143 if (ctype_ispointer(ct
->info
)) {
144 CTSize sz
= lj_ctype_size(cts
, ctype_cid(ct
->info
)); /* Element size. */
145 if (sz
== CTSIZE_INVALID
)
146 lj_err_caller(cts
->L
, LJ_ERR_FFI_INVSIZE
);
147 if (ctype_isptr(ct
->info
)) {
148 p
= (uint8_t *)cdata_getptr(p
, ct
->size
);
149 } else if ((ct
->info
& (CTF_VECTOR
|CTF_COMPLEX
))) {
150 if ((ct
->info
& CTF_COMPLEX
)) idx
&= 1;
151 *qual
|= CTF_CONST
; /* Valarray elements are constant. */
153 *pp
= p
+ idx
*(int32_t)sz
;
156 } else if (tviscdata(key
)) { /* Integer cdata key. */
157 GCcdata
*cdk
= cdataV(key
);
158 CType
*ctk
= ctype_raw(cts
, cdk
->ctypeid
);
159 if (ctype_isenum(ctk
->info
)) ctk
= ctype_child(cts
, ctk
);
160 if (ctype_isinteger(ctk
->info
)) {
161 lj_cconv_ct_ct(cts
, ctype_get(cts
, CTID_INT_PSZ
), ctk
,
162 (uint8_t *)&idx
, cdataptr(cdk
), 0);
165 } else if (tvisstr(key
)) { /* String key. */
166 GCstr
*name
= strV(key
);
167 if (ctype_isstruct(ct
->info
)) {
169 CType
*fct
= lj_ctype_getfieldq(cts
, ct
, name
, &ofs
, qual
);
174 } else if (ctype_iscomplex(ct
->info
)) {
175 if (name
->len
== 2) {
176 *qual
|= CTF_CONST
; /* Complex fields are constant. */
177 if (strdata(name
)[0] == 'r' && strdata(name
)[1] == 'e') {
180 } else if (strdata(name
)[0] == 'i' && strdata(name
)[1] == 'm') {
181 *pp
= p
+ (ct
->size
>> 1);
185 } else if (cd
->ctypeid
== CTID_CTYPEID
) {
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
)) {
192 CType
*fct
= lj_ctype_getfield(cts
, sct
, name
, &ofs
);
193 if (fct
&& ctype_isconstval(fct
->info
))
196 ct
= sct
; /* Allow resolving metamethods for constructors, too. */
199 if (ctype_isptr(ct
->info
)) { /* Automatically perform '->'. */
200 if (ctype_isstruct(ctype_rawchild(cts
, ct
)->info
)) {
201 p
= (uint8_t *)cdata_getptr(p
, ct
->size
);
202 ct
= ctype_child(cts
, ct
);
206 *qual
|= 1; /* Lookup failed. */
207 return ct
; /* But return the resolved raw type. */
210 /* -- C data getters ------------------------------------------------------ */
212 /* Get constant value and convert to TValue. */
213 static void cdata_getconst(CTState
*cts
, TValue
*o
, CType
*ct
)
215 CType
*ctt
= ctype_child(cts
, ct
);
216 lj_assertCTS(ctype_isinteger(ctt
->info
) && ctt
->size
<= 4,
217 "only 32 bit const supported"); /* NYI */
218 /* Constants are already zero-extended/sign-extended to 32 bits. */
219 if ((ctt
->info
& CTF_UNSIGNED
) && (int32_t)ct
->size
< 0)
220 setnumV(o
, (lua_Number
)(uint32_t)ct
->size
);
222 setintV(o
, (int32_t)ct
->size
);
225 /* Get C data value and convert to TValue. */
226 int lj_cdata_get(CTState
*cts
, CType
*s
, TValue
*o
, uint8_t *sp
)
230 if (ctype_isconstval(s
->info
)) {
231 cdata_getconst(cts
, o
, s
);
232 return 0; /* No GC step needed. */
233 } else if (ctype_isbitfield(s
->info
)) {
234 return lj_cconv_tv_bf(cts
, s
, o
, sp
);
237 /* Get child type of pointer/array/field. */
238 lj_assertCTS(ctype_ispointer(s
->info
) || ctype_isfield(s
->info
),
239 "pointer or field expected");
240 sid
= ctype_cid(s
->info
);
241 s
= ctype_get(cts
, sid
);
243 /* Resolve reference for field. */
244 if (ctype_isref(s
->info
)) {
245 lj_assertCTS(s
->size
== CTSIZE_PTR
, "ref is not pointer-sized");
246 sp
= *(uint8_t **)sp
;
247 sid
= ctype_cid(s
->info
);
248 s
= ctype_get(cts
, sid
);
251 /* Skip attributes. */
252 while (ctype_isattrib(s
->info
))
253 s
= ctype_child(cts
, s
);
255 return lj_cconv_tv_ct(cts
, s
, sid
, o
, sp
);
258 /* -- C data setters ------------------------------------------------------ */
260 /* Convert TValue and set C data value. */
261 void lj_cdata_set(CTState
*cts
, CType
*d
, uint8_t *dp
, TValue
*o
, CTInfo qual
)
263 if (ctype_isconstval(d
->info
)) {
265 } else if (ctype_isbitfield(d
->info
)) {
266 if (((d
->info
|qual
) & CTF_CONST
)) goto err_const
;
267 lj_cconv_bf_tv(cts
, d
, dp
, o
);
271 /* Get child type of pointer/array/field. */
272 lj_assertCTS(ctype_ispointer(d
->info
) || ctype_isfield(d
->info
),
273 "pointer or field expected");
274 d
= ctype_child(cts
, d
);
276 /* Resolve reference for field. */
277 if (ctype_isref(d
->info
)) {
278 lj_assertCTS(d
->size
== CTSIZE_PTR
, "ref is not pointer-sized");
279 dp
= *(uint8_t **)dp
;
280 d
= ctype_child(cts
, d
);
283 /* Skip attributes and collect qualifiers. */
285 if (ctype_isattrib(d
->info
)) {
286 if (ctype_attrib(d
->info
) == CTA_QUAL
) qual
|= d
->size
;
290 d
= ctype_child(cts
, d
);
293 lj_assertCTS(ctype_hassize(d
->info
), "store to ctype without size");
294 lj_assertCTS(!ctype_isvoid(d
->info
), "store to void type");
296 if (((d
->info
|qual
) & CTF_CONST
)) {
298 lj_err_caller(cts
->L
, LJ_ERR_FFI_WRCONST
);
301 lj_cconv_ct_tv(cts
, d
, dp
, o
, 0);