summaryrefslogtreecommitdiff
path: root/src/lib_ffi.c
diff options
context:
space:
mode:
authorMike Pall <mike>2011-01-26 21:46:02 +0100
committerMike Pall <mike>2011-01-26 21:46:02 +0100
commit3184f1716925f96b3d56c2795a0769bb3463f54e (patch)
treec9364c781e88b321ac4caffa566ccb5fa6659f83 /src/lib_ffi.c
parent2526498c7126f3e60d1f3a8d72c97bf20bf4a49e (diff)
downloadluajit-3184f1716925f96b3d56c2795a0769bb3463f54e.tar.gz
luajit-3184f1716925f96b3d56c2795a0769bb3463f54e.tar.bz2
luajit-3184f1716925f96b3d56c2795a0769bb3463f54e.zip
FFI: Move code for cdata arithmetic to lj_carith.c.
Diffstat (limited to 'src/lib_ffi.c')
-rw-r--r--src/lib_ffi.c217
1 files changed, 8 insertions, 209 deletions
diff --git a/src/lib_ffi.c b/src/lib_ffi.c
index 42d71153..ef5de029 100644
--- a/src/lib_ffi.c
+++ b/src/lib_ffi.c
@@ -21,6 +21,7 @@
21#include "lj_cparse.h" 21#include "lj_cparse.h"
22#include "lj_cdata.h" 22#include "lj_cdata.h"
23#include "lj_cconv.h" 23#include "lj_cconv.h"
24#include "lj_carith.h"
24#include "lj_ccall.h" 25#include "lj_ccall.h"
25#include "lj_clib.h" 26#include "lj_clib.h"
26#include "lj_ff.h" 27#include "lj_ff.h"
@@ -77,215 +78,6 @@ static void *ffi_checkptr(lua_State *L, int narg, CTypeID id)
77 return p; 78 return p;
78} 79}
79 80
80/* -- C data arithmetic --------------------------------------------------- */
81
82typedef struct FFIArith {
83 uint8_t *p[2];
84 CType *ct[2];
85} FFIArith;
86
87/* Check arguments for arithmetic metamethods. */
88static int ffi_checkarith(lua_State *L, CTState *cts, FFIArith *fa)
89{
90 TValue *o = L->base;
91 int ok = 1;
92 MSize i;
93 if (o+1 >= L->top)
94 lj_err_argt(L, 1, LUA_TCDATA);
95 for (i = 0; i < 2; i++, o++) {
96 if (tviscdata(o)) {
97 GCcdata *cd = cdataV(o);
98 CType *ct = ctype_raw(cts, (CTypeID)cd->typeid);
99 uint8_t *p = (uint8_t *)cdataptr(cd);
100 if (ctype_isptr(ct->info)) {
101 p = (uint8_t *)cdata_getptr(p, ct->size);
102 if (ctype_isref(ct->info)) ct = ctype_rawchild(cts, ct);
103 }
104 fa->ct[i] = ct;
105 fa->p[i] = p;
106 } else if (tvisnum(o)) {
107 fa->ct[i] = ctype_get(cts, CTID_DOUBLE);
108 fa->p[i] = (uint8_t *)&o->n;
109 } else if (tvisnil(o)) {
110 fa->ct[i] = ctype_get(cts, CTID_P_VOID);
111 fa->p[i] = (uint8_t *)0;
112 } else {
113 fa->ct[i] = NULL;
114 fa->p[i] = NULL;
115 ok = 0;
116 }
117 }
118 return ok;
119}
120
121/* Pointer arithmetic. */
122static int ffi_arith_ptr(lua_State *L, CTState *cts, FFIArith *fa, MMS mm)
123{
124 CType *ctp = fa->ct[0];
125 uint8_t *pp = fa->p[0];
126 ptrdiff_t idx;
127 CTSize sz;
128 CTypeID id;
129 GCcdata *cd;
130 if (ctype_isptr(ctp->info) || ctype_isrefarray(ctp->info)) {
131 if ((mm == MM_sub || mm == MM_eq || mm == MM_lt || mm == MM_le) &&
132 (ctype_isptr(fa->ct[1]->info) || ctype_isrefarray(fa->ct[1]->info))) {
133 uint8_t *pp2 = fa->p[1];
134 if (mm == MM_eq) { /* Pointer equality. Incompatible pointers are ok. */
135 setboolV(L->top-1, (pp == pp2));
136 return 1;
137 }
138 if (!lj_cconv_compatptr(cts, ctp, fa->ct[1], CCF_IGNQUAL))
139 return 0;
140 if (mm == MM_sub) { /* Pointer difference. */
141 intptr_t diff;
142 sz = lj_ctype_size(cts, ctype_cid(ctp->info)); /* Element size. */
143 if (sz == 0 || sz == CTSIZE_INVALID)
144 return 0;
145 diff = ((intptr_t)pp - (intptr_t)pp2) / (int32_t)sz;
146 /* All valid pointer differences on x64 are in (-2^47, +2^47),
147 ** which fits into a double without loss of precision.
148 */
149 setnumV(L->top-1, (lua_Number)diff);
150 return 1;
151 } else if (mm == MM_lt) { /* Pointer comparison (unsigned). */
152 setboolV(L->top-1, ((uintptr_t)pp < (uintptr_t)pp2));
153 return 1;
154 } else {
155 lua_assert(mm == MM_le);
156 setboolV(L->top-1, ((uintptr_t)pp <= (uintptr_t)pp2));
157 return 1;
158 }
159 }
160 if (!((mm == MM_add || mm == MM_sub) && ctype_isnum(fa->ct[1]->info)))
161 return 0;
162 lj_cconv_ct_ct(cts, ctype_get(cts, CTID_INT_PSZ), fa->ct[1],
163 (uint8_t *)&idx, fa->p[1], 0);
164 if (mm == MM_sub) idx = -idx;
165 } else if (mm == MM_add && ctype_isnum(ctp->info) &&
166 (ctype_isptr(fa->ct[1]->info) || ctype_isrefarray(fa->ct[1]->info))) {
167 /* Swap pointer and index. */
168 ctp = fa->ct[1]; pp = fa->p[1];
169 lj_cconv_ct_ct(cts, ctype_get(cts, CTID_INT_PSZ), fa->ct[0],
170 (uint8_t *)&idx, fa->p[0], 0);
171 } else {
172 return 0;
173 }
174 sz = lj_ctype_size(cts, ctype_cid(ctp->info)); /* Element size. */
175 if (sz == CTSIZE_INVALID)
176 return 0;
177 pp += idx*(int32_t)sz; /* Compute pointer + index. */
178 id = lj_ctype_intern(cts, CTINFO(CT_PTR, CTALIGN_PTR|ctype_cid(ctp->info)),
179 CTSIZE_PTR);
180 cd = lj_cdata_new(cts, id, CTSIZE_PTR);
181 *(uint8_t **)cdataptr(cd) = pp;
182 setcdataV(L, L->top-1, cd);
183 lj_gc_check(L);
184 return 1;
185}
186
187/* 64 bit integer arithmetic. */
188static int ffi_arith_int64(lua_State *L, CTState *cts, FFIArith *fa, MMS mm)
189{
190 if (ctype_isnum(fa->ct[0]->info) && fa->ct[0]->size <= 8 &&
191 ctype_isnum(fa->ct[1]->info) && fa->ct[1]->size <= 8) {
192 CTypeID id = (((fa->ct[0]->info & CTF_UNSIGNED) && fa->ct[0]->size == 8) ||
193 ((fa->ct[1]->info & CTF_UNSIGNED) && fa->ct[1]->size == 8)) ?
194 CTID_UINT64 : CTID_INT64;
195 CType *ct = ctype_get(cts, id);
196 GCcdata *cd;
197 uint64_t u0, u1, *up;
198 lj_cconv_ct_ct(cts, ct, fa->ct[0], (uint8_t *)&u0, fa->p[0], 0);
199 if (mm != MM_unm)
200 lj_cconv_ct_ct(cts, ct, fa->ct[1], (uint8_t *)&u1, fa->p[1], 0);
201 switch (mm) {
202 case MM_eq:
203 setboolV(L->top-1, (u0 == u1));
204 return 1;
205 case MM_lt:
206 setboolV(L->top-1,
207 id == CTID_INT64 ? ((int64_t)u0 < (int64_t)u1) : (u0 < u1));
208 return 1;
209 case MM_le:
210 setboolV(L->top-1,
211 id == CTID_INT64 ? ((int64_t)u0 <= (int64_t)u1) : (u0 <= u1));
212 return 1;
213 case MM_div: case MM_mod:
214 if (u1 == 0) { /* Division by zero. */
215 if (u0 == 0)
216 setnanV(L->top-1);
217 else if (id == CTID_INT64 && (int64_t)u0 < 0)
218 setminfV(L->top-1);
219 else
220 setpinfV(L->top-1);
221 return 1;
222 } else if (id == CTID_INT64 && (int64_t)u1 == -1 &&
223 u0 == U64x(80000000,00000000)) { /* MIN64 / -1. */
224 if (mm == MM_div) id = CTID_UINT64; else u0 = 0;
225 mm = MM_unm; /* Result is 0x8000000000000000ULL or 0LL. */
226 }
227 break;
228 default: break;
229 }
230 cd = lj_cdata_new(cts, id, 8);
231 up = (uint64_t *)cdataptr(cd);
232 setcdataV(L, L->top-1, cd);
233 switch (mm) {
234 case MM_add: *up = u0 + u1; break;
235 case MM_sub: *up = u0 - u1; break;
236 case MM_mul: *up = u0 * u1; break;
237 case MM_div:
238 if (id == CTID_INT64)
239 *up = (uint64_t)((int64_t)u0 / (int64_t)u1);
240 else
241 *up = u0 / u1;
242 break;
243 case MM_mod:
244 if (id == CTID_INT64)
245 *up = (uint64_t)((int64_t)u0 % (int64_t)u1);
246 else
247 *up = u0 % u1;
248 break;
249 case MM_pow: *up = lj_cdata_powi64(u0, u1, (id == CTID_UINT64)); break;
250 case MM_unm: *up = (uint64_t)-(int64_t)u0; break;
251 default: lua_assert(0); break;
252 }
253 lj_gc_check(L);
254 return 1;
255 }
256 return 0;
257}
258
259/* cdata arithmetic. */
260static int ffi_arith(lua_State *L)
261{
262 CTState *cts = ctype_cts(L);
263 FFIArith fa;
264 MMS mm = (MMS)(curr_func(L)->c.ffid - (int)FF_ffi_meta___eq + (int)MM_eq);
265 if (ffi_checkarith(L, cts, &fa)) {
266 if (ffi_arith_int64(L, cts, &fa, mm) || ffi_arith_ptr(L, cts, &fa, mm)) {
267 copyTV(L, &G(L)->tmptv2, L->top-1); /* Remember for trace recorder. */
268 return 1;
269 }
270 }
271 /* NYI: per-cdata metamethods. */
272 {
273 const char *repr[2];
274 int i;
275 for (i = 0; i < 2; i++) {
276 if (fa.ct[i])
277 repr[i] = strdata(lj_ctype_repr(L, ctype_typeid(cts, fa.ct[i]), NULL));
278 else
279 repr[i] = typename(&L->base[i]);
280 }
281 lj_err_callerv(L, mm == MM_len ? LJ_ERR_FFI_BADLEN :
282 mm == MM_concat ? LJ_ERR_FFI_BADCONCAT :
283 mm < MM_add ? LJ_ERR_FFI_BADCOMP : LJ_ERR_FFI_BADARITH,
284 repr[0], repr[1]);
285 }
286 return 0; /* unreachable */
287}
288
289/* -- C type metamethods -------------------------------------------------- */ 81/* -- C type metamethods -------------------------------------------------- */
290 82
291#define LJLIB_MODULE_ffi_meta 83#define LJLIB_MODULE_ffi_meta
@@ -319,6 +111,13 @@ LJLIB_CF(ffi_meta___newindex) LJLIB_REC(cdata_index 1)
319 return 0; 111 return 0;
320} 112}
321 113
114/* Common handler for cdata arithmetic. */
115static int ffi_arith(lua_State *L)
116{
117 MMS mm = (MMS)(curr_func(L)->c.ffid - (int)FF_ffi_meta___eq + (int)MM_eq);
118 return lj_carith_op(L, mm);
119}
120
322/* The following functions must be in contiguous ORDER MM. */ 121/* The following functions must be in contiguous ORDER MM. */
323LJLIB_CF(ffi_meta___eq) LJLIB_REC(cdata_arith MM_eq) 122LJLIB_CF(ffi_meta___eq) LJLIB_REC(cdata_arith MM_eq)
324{ 123{