diff options
author | Mike Pall <mike> | 2010-12-05 00:18:07 +0100 |
---|---|---|
committer | Mike Pall <mike> | 2010-12-05 00:18:07 +0100 |
commit | 526e087e63daaaeab517932351c8941f678e071c (patch) | |
tree | e7a1460ba4c120b1cc464a3702fb915de9388fe9 /src/lj_cdata.c | |
parent | 05973ee44075698e6c578cfb0fa72cfccdf7b742 (diff) | |
download | luajit-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.c | 235 |
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. */ | ||
20 | GCcdata *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. */ | ||
29 | GCcdata *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. */ | ||
53 | void 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. */ | ||
68 | CType *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. */ | ||
147 | static 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. */ | ||
159 | void 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. */ | ||
194 | void 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 | ||