aboutsummaryrefslogtreecommitdiff
path: root/src/lj_cdata.c
diff options
context:
space:
mode:
authorMike Pall <mike>2010-12-05 00:18:07 +0100
committerMike Pall <mike>2010-12-05 00:18:07 +0100
commit526e087e63daaaeab517932351c8941f678e071c (patch)
treee7a1460ba4c120b1cc464a3702fb915de9388fe9 /src/lj_cdata.c
parent05973ee44075698e6c578cfb0fa72cfccdf7b742 (diff)
downloadluajit-526e087e63daaaeab517932351c8941f678e071c.tar.gz
luajit-526e087e63daaaeab517932351c8941f678e071c.tar.bz2
luajit-526e087e63daaaeab517932351c8941f678e071c.zip
FFI: Add C data handling and C type conversions.
Diffstat (limited to 'src/lj_cdata.c')
-rw-r--r--src/lj_cdata.c235
1 files changed, 235 insertions, 0 deletions
diff --git a/src/lj_cdata.c b/src/lj_cdata.c
new file mode 100644
index 00000000..15ba2dde
--- /dev/null
+++ b/src/lj_cdata.c
@@ -0,0 +1,235 @@
1/*
2** C data management.
3** Copyright (C) 2005-2010 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_ctype.h"
14#include "lj_cconv.h"
15#include "lj_cdata.h"
16
17/* -- C data allocation --------------------------------------------------- */
18
19/* Allocate a new C data object holding a reference to another object. */
20GCcdata *lj_cdata_newref(CTState *cts, const void *p, CTypeID id)
21{
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;
25 return cd;
26}
27
28/* Allocate variable-sized or specially aligned C data object. */
29GCcdata *lj_cdata_newv(CTState *cts, CTypeID id, CTSize sz, CTSize align)
30{
31 global_State *g;
32 MSize extra = sizeof(GCcdataVar) + sizeof(GCcdata) +
33 (align > CT_MEMALIGN ? (1u<<align) - (1u<<CT_MEMALIGN) : 0);
34 char *p = lj_mem_newt(cts->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 lua_assert((char *)cd - p < 65536);
39 cdatav(cd)->offset = (uint16_t)((char *)cd - p);
40 cdatav(cd)->extra = extra;
41 cdatav(cd)->len = sz;
42 g = cts->g;
43 setgcrefr(cd->nextgc, g->gc.root);
44 setgcref(g->gc.root, obj2gco(cd));
45 newwhite(g, obj2gco(cd));
46 cd->marked |= 0x80;
47 cd->gct = ~LJ_TCDATA;
48 cd->typeid = id;
49 return cd;
50}
51
52/* Free a C data object. */
53void LJ_FASTCALL lj_cdata_free(global_State *g, GCcdata *cd)
54{
55 if (LJ_LIKELY(!cdataisv(cd))) {
56 CType *ct = ctype_raw(ctype_ctsG(g), cd->typeid);
57 CTSize sz = ctype_hassize(ct->info) ? ct->size : CTSIZE_PTR;
58 lua_assert(ctype_hassize(ct->info) || ctype_isfunc(ct->info));
59 lj_mem_free(g, cd, sizeof(GCcdata) + sz);
60 } else {
61 lj_mem_free(g, memcdatav(cd), sizecdatav(cd));
62 }
63}
64
65/* -- C data indexing ----------------------------------------------------- */
66
67/* Index C data by a TValue. Return CType and pointer. */
68CType *lj_cdata_index(CTState *cts, GCcdata *cd, cTValue *key, uint8_t **pp,
69 CTInfo *qual)
70{
71 uint8_t *p = (uint8_t *)cdataptr(cd);
72 CType *ct = ctype_get(cts, cd->typeid);
73
74 /* Resolve reference for cdata object. */
75 if (ctype_isref(ct->info)) {
76 lua_assert(ct->size == CTSIZE_PTR);
77 p = *(uint8_t **)p;
78 ct = ctype_child(cts, ct);
79 }
80
81 /* Skip attributes and collect qualifiers. */
82 while (ctype_isattrib(ct->info)) {
83 if (ctype_attrib(ct->info) == CTA_QUAL) *qual |= ct->size;
84 ct = ctype_child(cts, ct);
85 }
86 lua_assert(!ctype_isref(ct->info)); /* Interning rejects refs to refs. */
87
88 if (tvisnum(key)) { /* Numeric key. */
89 ptrdiff_t idx = LJ_64 ? (ptrdiff_t)numV(key) :
90 (ptrdiff_t)lj_num2int(numV(key));
91 if (ctype_ispointer(ct->info)) {
92 CTSize sz = lj_ctype_size(cts, ctype_cid(ct->info));
93 if (sz != CTSIZE_INVALID) {
94 if (ctype_isptr(ct->info))
95 p = (uint8_t *)cdata_getptr(p, ct->size);
96 else if ((ct->info & (CTF_VECTOR|CTF_COMPLEX)))
97 *qual |= CTF_CONST; /* Valarray elements are constant. */
98 *pp = p + idx*(int32_t)sz;
99 return ct;
100 }
101 }
102 } else if (tvisstr(key)) { /* String key. */
103 GCstr *name = strV(key);
104 if (ctype_isptr(ct->info)) { /* Automatically perform '->'. */
105 CType *cct = ctype_child(cts, ct);
106 if (ctype_isstruct(cct->info)) {
107 p = (uint8_t *)cdata_getptr(p, ct->size);
108 ct = cct;
109 goto index_struct;
110 }
111 } if (ctype_isstruct(ct->info)) {
112 CTSize ofs;
113 CType *fct;
114 index_struct:
115 fct = lj_ctype_getfield(cts, ct, name, &ofs);
116 if (fct) {
117 *pp = p + ofs;
118 return fct;
119 }
120 } else if (ctype_iscomplex(ct->info)) {
121 if (name->len == 2) {
122 *qual |= CTF_CONST; /* Complex fields are constant. */
123 if (strdata(name)[0] == 'r' && strdata(name)[1] == 'e') {
124 *pp = p;
125 return ct;
126 } else if (strdata(name)[0] == 'i' && strdata(name)[1] == 'm') {
127 *pp = p + (ct->size >> 1);
128 return ct;
129 }
130 }
131 }
132 {
133 GCstr *s = lj_ctype_repr(cts->L, ctype_typeid(cts, ct), NULL);
134 lj_err_callerv(cts->L, LJ_ERR_FFI_BADMEMBER, strdata(s), strdata(name));
135 }
136 }
137 {
138 GCstr *s = lj_ctype_repr(cts->L, ctype_typeid(cts, ct), NULL);
139 lj_err_callerv(cts->L, LJ_ERR_FFI_BADIDX, strdata(s));
140 }
141 return NULL; /* unreachable */
142}
143
144/* -- C data getters ------------------------------------------------------ */
145
146/* Get constant value and convert to TValue. */
147static void cdata_getconst(CTState *cts, TValue *o, CType *ct)
148{
149 CType *ctt = ctype_child(cts, ct);
150 lua_assert(ctype_isinteger(ctt->info) && ctt->size <= 4);
151 /* Constants are already zero-extended/sign-extended to 32 bits. */
152 if (!(ctt->info & CTF_UNSIGNED))
153 setintV(o, (int32_t)ct->size);
154 else
155 setnumV(o, (lua_Number)(uint32_t)ct->size);
156}
157
158/* Get C data value and convert to TValue. */
159void lj_cdata_get(CTState *cts, CType *s, TValue *o, uint8_t *sp)
160{
161 CTypeID sid;
162
163 if (ctype_isconstval(s->info)) {
164 cdata_getconst(cts, o, s);
165 return;
166 } else if (ctype_isbitfield(s->info)) {
167 lj_cconv_tv_bf(cts, s, o, sp);
168 return;
169 }
170
171 /* Get child type of pointer/array/field. */
172 lua_assert(ctype_ispointer(s->info) || ctype_isfield(s->info));
173 sid = ctype_cid(s->info);
174 s = ctype_get(cts, sid);
175
176 /* Resolve reference for field. */
177 if (ctype_isref(s->info)) {
178 lua_assert(s->size == CTSIZE_PTR);
179 sp = *(uint8_t **)sp;
180 sid = ctype_cid(s->info);
181 s = ctype_get(cts, sid);
182 }
183
184 /* Skip attributes and enums. */
185 while (ctype_isattrib(s->info) || ctype_isenum(s->info))
186 s = ctype_child(cts, s);
187
188 lj_cconv_tv_ct(cts, s, sid, o, sp);
189}
190
191/* -- C data setters ------------------------------------------------------ */
192
193/* Convert TValue and set C data value. */
194void lj_cdata_set(CTState *cts, CType *d, uint8_t *dp, TValue *o, CTInfo qual)
195{
196 if (ctype_isconstval(d->info)) {
197 goto err_const;
198 } else if (ctype_isbitfield(d->info)) {
199 if (((d->info|qual) & CTF_CONST)) goto err_const;
200 lj_cconv_bf_tv(cts, d, dp, o);
201 return;
202 }
203
204 /* Get child type of pointer/array/field. */
205 lua_assert(ctype_ispointer(d->info) || ctype_isfield(d->info));
206 d = ctype_child(cts, d);
207
208 /* Resolve reference for field. */
209 if (ctype_isref(d->info)) {
210 lua_assert(d->size == CTSIZE_PTR);
211 dp = *(uint8_t **)dp;
212 d = ctype_child(cts, d);
213 }
214
215 /* Skip attributes and collect qualifiers. */
216 for (;;) {
217 if (ctype_isattrib(d->info)) {
218 if (ctype_attrib(d->info) == CTA_QUAL) qual |= d->size;
219 } else {
220 break;
221 }
222 d = ctype_child(cts, d);
223 }
224
225 lua_assert(ctype_hassize(d->info) && !ctype_isvoid(d->info));
226
227 if (((d->info|qual) & CTF_CONST)) {
228 err_const:
229 lj_err_caller(cts->L, LJ_ERR_FFI_WRCONST);
230 }
231
232 lj_cconv_ct_tv(cts, d, dp, o, 0);
233}
234
235#endif