diff options
author | Mike Pall <mike> | 2010-12-25 22:54:25 +0100 |
---|---|---|
committer | Mike Pall <mike> | 2010-12-25 22:54:25 +0100 |
commit | 44935dae0d6b07b07ade4db7ffddc0268767bc43 (patch) | |
tree | faa3e21c9cac6a02b9a777f4cb921ff2c1792472 /src/lib_ffi.c | |
parent | dd65e00831745a5fb9b29be2188d2d094f350e88 (diff) | |
download | luajit-44935dae0d6b07b07ade4db7ffddc0268767bc43.tar.gz luajit-44935dae0d6b07b07ade4db7ffddc0268767bc43.tar.bz2 luajit-44935dae0d6b07b07ade4db7ffddc0268767bc43.zip |
FFI: Add 64 bit integer arithmetic.
Diffstat (limited to 'src/lib_ffi.c')
-rw-r--r-- | src/lib_ffi.c | 127 |
1 files changed, 111 insertions, 16 deletions
diff --git a/src/lib_ffi.c b/src/lib_ffi.c index 3ea19dd5..c674582d 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_ff.h" | ||
24 | #include "lj_lib.h" | 25 | #include "lj_lib.h" |
25 | 26 | ||
26 | /* -- C type checks ------------------------------------------------------- */ | 27 | /* -- C type checks ------------------------------------------------------- */ |
@@ -80,9 +81,8 @@ typedef struct FFIArith { | |||
80 | } FFIArith; | 81 | } FFIArith; |
81 | 82 | ||
82 | /* Check arguments for arithmetic metamethods. */ | 83 | /* Check arguments for arithmetic metamethods. */ |
83 | static void ffi_checkarith(lua_State *L, FFIArith *fa) | 84 | static void ffi_checkarith(lua_State *L, CTState *cts, FFIArith *fa) |
84 | { | 85 | { |
85 | CTState *cts = ctype_cts(L); | ||
86 | TValue *o = L->base; | 86 | TValue *o = L->base; |
87 | MSize i; | 87 | MSize i; |
88 | if (o+1 >= L->top) | 88 | if (o+1 >= L->top) |
@@ -154,17 +154,18 @@ LJLIB_CF(ffi_meta___call) LJLIB_REC(cdata_call) | |||
154 | } | 154 | } |
155 | 155 | ||
156 | /* Pointer arithmetic. */ | 156 | /* Pointer arithmetic. */ |
157 | static int ffi_arith_ptr(lua_State *L, FFIArith *fa, int sub) | 157 | static int ffi_arith_ptr(lua_State *L, CTState *cts, FFIArith *fa, MMS mm) |
158 | { | 158 | { |
159 | CTState *cts = ctype_cts(L); | ||
160 | CType *ctp = fa->ct[0]; | 159 | CType *ctp = fa->ct[0]; |
161 | uint8_t *pp = fa->p[0]; | 160 | uint8_t *pp = fa->p[0]; |
162 | ptrdiff_t idx; | 161 | ptrdiff_t idx; |
163 | CTSize sz; | 162 | CTSize sz; |
164 | CTypeID id; | 163 | CTypeID id; |
165 | GCcdata *cd; | 164 | GCcdata *cd; |
165 | if (!(mm == MM_add || mm == MM_sub)) | ||
166 | return 0; | ||
166 | if (ctype_isptr(ctp->info) || ctype_isrefarray(ctp->info)) { | 167 | if (ctype_isptr(ctp->info) || ctype_isrefarray(ctp->info)) { |
167 | if (sub && | 168 | if (mm == MM_sub && |
168 | (ctype_isptr(fa->ct[1]->info) || ctype_isrefarray(fa->ct[1]->info))) { | 169 | (ctype_isptr(fa->ct[1]->info) || ctype_isrefarray(fa->ct[1]->info))) { |
169 | /* Pointer difference. */ | 170 | /* Pointer difference. */ |
170 | intptr_t diff; | 171 | intptr_t diff; |
@@ -184,11 +185,13 @@ static int ffi_arith_ptr(lua_State *L, FFIArith *fa, int sub) | |||
184 | setnumV(L->top-1, (lua_Number)diff); | 185 | setnumV(L->top-1, (lua_Number)diff); |
185 | return 1; | 186 | return 1; |
186 | } | 187 | } |
188 | if (!ctype_isnum(fa->ct[1]->info)) return 0; | ||
187 | lj_cconv_ct_ct(cts, ctype_get(cts, CTID_INT_PSZ), fa->ct[1], | 189 | lj_cconv_ct_ct(cts, ctype_get(cts, CTID_INT_PSZ), fa->ct[1], |
188 | (uint8_t *)&idx, fa->p[1], 0); | 190 | (uint8_t *)&idx, fa->p[1], 0); |
189 | if (sub) idx = -idx; | 191 | if (mm == MM_sub) idx = -idx; |
190 | } else if (!sub && | 192 | } else if (mm == MM_add && |
191 | (ctype_isptr(fa->ct[1]->info) || ctype_isrefarray(fa->ct[1]->info))) { | 193 | (ctype_isptr(fa->ct[1]->info) || ctype_isrefarray(fa->ct[1]->info))) { |
194 | if (!ctype_isnum(ctp->info)) return 0; | ||
192 | /* Swap pointer and index. */ | 195 | /* Swap pointer and index. */ |
193 | ctp = fa->ct[1]; pp = fa->p[1]; | 196 | ctp = fa->ct[1]; pp = fa->p[1]; |
194 | lj_cconv_ct_ct(cts, ctype_get(cts, CTID_INT_PSZ), fa->ct[0], | 197 | lj_cconv_ct_ct(cts, ctype_get(cts, CTID_INT_PSZ), fa->ct[0], |
@@ -210,22 +213,114 @@ static int ffi_arith_ptr(lua_State *L, FFIArith *fa, int sub) | |||
210 | return 1; | 213 | return 1; |
211 | } | 214 | } |
212 | 215 | ||
213 | LJLIB_CF(ffi_meta___add) | 216 | /* 64 bit integer arithmetic. */ |
217 | static int ffi_arith_int64(lua_State *L, CTState *cts, FFIArith *fa, MMS mm) | ||
214 | { | 218 | { |
219 | if (ctype_isnum(fa->ct[0]->info) && fa->ct[0]->size <= 8 && | ||
220 | ctype_isnum(fa->ct[1]->info) && fa->ct[1]->size <= 8) { | ||
221 | CTypeID id = (((fa->ct[0]->info & CTF_UNSIGNED) && fa->ct[0]->size == 8) || | ||
222 | ((fa->ct[1]->info & CTF_UNSIGNED) && fa->ct[1]->size == 8)) ? | ||
223 | CTID_UINT64 : CTID_INT64; | ||
224 | CType *ct = ctype_get(cts, id); | ||
225 | GCcdata *cd; | ||
226 | uint64_t u0, u1, *up; | ||
227 | lj_cconv_ct_ct(cts, ct, fa->ct[0], (uint8_t *)&u0, fa->p[0], 0); | ||
228 | if (mm != MM_unm) | ||
229 | lj_cconv_ct_ct(cts, ct, fa->ct[1], (uint8_t *)&u1, fa->p[1], 0); | ||
230 | if ((mm == MM_div || mm == MM_mod)) { | ||
231 | if (u1 == 0) { /* Division by zero. */ | ||
232 | if (u0 == 0) | ||
233 | setnanV(L->top-1); | ||
234 | else if (id == CTID_INT64 && (int64_t)u0 < 0) | ||
235 | setminfV(L->top-1); | ||
236 | else | ||
237 | setpinfV(L->top-1); | ||
238 | return 1; | ||
239 | } else if (id == CTID_INT64 && (int64_t)u1 == -1 && | ||
240 | u0 == U64x(80000000,00000000)) { /* MIN64 / -1. */ | ||
241 | if (mm == MM_div) id = CTID_UINT64; else u0 = 0; | ||
242 | mm = MM_unm; /* Result is 0x8000000000000000ULL or 0LL. */ | ||
243 | } | ||
244 | } | ||
245 | cd = lj_cdata_new(cts, id, 8); | ||
246 | up = (uint64_t *)cdataptr(cd); | ||
247 | setcdataV(L, L->top-1, cd); | ||
248 | switch (mm) { | ||
249 | case MM_add: *up = u0 + u1; break; | ||
250 | case MM_sub: *up = u0 - u1; break; | ||
251 | case MM_mul: *up = u0 * u1; break; | ||
252 | case MM_div: | ||
253 | if (id == CTID_INT64) | ||
254 | *up = (uint64_t)((int64_t)u0 / (int64_t)u1); | ||
255 | else | ||
256 | *up = u0 / u1; | ||
257 | break; | ||
258 | case MM_mod: | ||
259 | if (id == CTID_INT64) | ||
260 | *up = (uint64_t)((int64_t)u0 % (int64_t)u1); | ||
261 | else | ||
262 | *up = u0 % u1; | ||
263 | break; | ||
264 | case MM_pow: *up = lj_cdata_powi64(u0, u1, (id == CTID_UINT64)); break; | ||
265 | case MM_unm: *up = -u0; break; | ||
266 | default: lua_assert(0); break; | ||
267 | } | ||
268 | return 1; | ||
269 | } | ||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | /* cdata arithmetic. */ | ||
274 | static int ffi_arith(lua_State *L) | ||
275 | { | ||
276 | CTState *cts = ctype_cts(L); | ||
215 | FFIArith fa; | 277 | FFIArith fa; |
216 | ffi_checkarith(L, &fa); | 278 | MMS mm = (MMS)(curr_func(L)->c.ffid - (int)FF_ffi_meta___add + (int)MM_add); |
217 | if (!ffi_arith_ptr(L, &fa, 0)) | 279 | ffi_checkarith(L, cts, &fa); |
218 | lj_err_caller(L, LJ_ERR_FFI_INVTYPE); | 280 | if (!ffi_arith_int64(L, cts, &fa, mm) && |
281 | !ffi_arith_ptr(L, cts, &fa, mm)) { | ||
282 | const char *repr[2]; | ||
283 | int i; | ||
284 | for (i = 0; i < 2; i++) | ||
285 | repr[i] = strdata(lj_ctype_repr(L, ctype_typeid(cts, fa.ct[i]), NULL)); | ||
286 | lj_err_callerv(L, LJ_ERR_FFI_BADARITH, repr[0], repr[1]); | ||
287 | } | ||
219 | return 1; | 288 | return 1; |
220 | } | 289 | } |
221 | 290 | ||
291 | LJLIB_CF(ffi_meta___add) | ||
292 | { | ||
293 | return ffi_arith(L); | ||
294 | } | ||
295 | |||
222 | LJLIB_CF(ffi_meta___sub) | 296 | LJLIB_CF(ffi_meta___sub) |
223 | { | 297 | { |
224 | FFIArith fa; | 298 | return ffi_arith(L); |
225 | ffi_checkarith(L, &fa); | 299 | } |
226 | if (!ffi_arith_ptr(L, &fa, 1)) | 300 | |
227 | lj_err_caller(L, LJ_ERR_FFI_INVTYPE); | 301 | LJLIB_CF(ffi_meta___mul) |
228 | return 1; | 302 | { |
303 | return ffi_arith(L); | ||
304 | } | ||
305 | |||
306 | LJLIB_CF(ffi_meta___div) | ||
307 | { | ||
308 | return ffi_arith(L); | ||
309 | } | ||
310 | |||
311 | LJLIB_CF(ffi_meta___mod) | ||
312 | { | ||
313 | return ffi_arith(L); | ||
314 | } | ||
315 | |||
316 | LJLIB_CF(ffi_meta___pow) | ||
317 | { | ||
318 | return ffi_arith(L); | ||
319 | } | ||
320 | |||
321 | LJLIB_CF(ffi_meta___unm) | ||
322 | { | ||
323 | return ffi_arith(L); | ||
229 | } | 324 | } |
230 | 325 | ||
231 | LJLIB_CF(ffi_meta___tostring) | 326 | LJLIB_CF(ffi_meta___tostring) |