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 | |
| parent | dd65e00831745a5fb9b29be2188d2d094f350e88 (diff) | |
| download | luajit-44935dae0d6b07b07ade4db7ffddc0268767bc43.tar.gz luajit-44935dae0d6b07b07ade4db7ffddc0268767bc43.tar.bz2 luajit-44935dae0d6b07b07ade4db7ffddc0268767bc43.zip | |
FFI: Add 64 bit integer arithmetic.
| -rw-r--r-- | src/Makefile.dep | 2 | ||||
| -rw-r--r-- | src/lib_ffi.c | 127 | ||||
| -rw-r--r-- | src/lj_cdata.c | 40 | ||||
| -rw-r--r-- | src/lj_cdata.h | 2 | ||||
| -rw-r--r-- | src/lj_errmsg.h | 1 | ||||
| -rw-r--r-- | src/lj_obj.h | 2 |
6 files changed, 157 insertions, 17 deletions
diff --git a/src/Makefile.dep b/src/Makefile.dep index 3e202537..31c54bcf 100644 --- a/src/Makefile.dep +++ b/src/Makefile.dep | |||
| @@ -22,7 +22,7 @@ lib_debug.o: lib_debug.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \ | |||
| 22 | lj_def.h lj_arch.h lj_err.h lj_errmsg.h lj_lib.h lj_libdef.h | 22 | lj_def.h lj_arch.h lj_err.h lj_errmsg.h lj_lib.h lj_libdef.h |
| 23 | lib_ffi.o: lib_ffi.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \ | 23 | lib_ffi.o: lib_ffi.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \ |
| 24 | lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_ctype.h lj_cparse.h \ | 24 | lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_ctype.h lj_cparse.h \ |
| 25 | lj_cdata.h lj_cconv.h lj_lib.h lj_libdef.h | 25 | lj_cdata.h lj_cconv.h lj_ff.h lj_ffdef.h lj_lib.h lj_libdef.h |
| 26 | lib_init.o: lib_init.c lua.h luaconf.h lauxlib.h lualib.h lj_arch.h | 26 | lib_init.o: lib_init.c lua.h luaconf.h lauxlib.h lualib.h lj_arch.h |
| 27 | lib_io.o: lib_io.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \ | 27 | lib_io.o: lib_io.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \ |
| 28 | lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_ff.h lj_ffdef.h \ | 28 | lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_ff.h lj_ffdef.h \ |
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) |
diff --git a/src/lj_cdata.c b/src/lj_cdata.c index a763908d..499dbc4d 100644 --- a/src/lj_cdata.c +++ b/src/lj_cdata.c | |||
| @@ -230,4 +230,44 @@ void lj_cdata_set(CTState *cts, CType *d, uint8_t *dp, TValue *o, CTInfo qual) | |||
| 230 | lj_cconv_ct_tv(cts, d, dp, o, 0); | 230 | lj_cconv_ct_tv(cts, d, dp, o, 0); |
| 231 | } | 231 | } |
| 232 | 232 | ||
| 233 | /* -- 64 bit integer arithmetic helpers ----------------------------------- */ | ||
| 234 | |||
| 235 | /* 64 bit integer x^k. */ | ||
| 236 | uint64_t lj_cdata_powi64(uint64_t x, uint64_t k, int isunsigned) | ||
| 237 | { | ||
| 238 | uint64_t y = 0; | ||
| 239 | int sign = 0; | ||
| 240 | if (k == 0) | ||
| 241 | return 1; | ||
| 242 | if (!isunsigned) { | ||
| 243 | if ((int64_t)k < 0) { | ||
| 244 | if (x == 0) | ||
| 245 | return U64x(7fffffff,ffffffff); | ||
| 246 | else if (x == 1) | ||
| 247 | return 1; | ||
| 248 | else if ((int64_t)x == -1) | ||
| 249 | return (k & 1) ? -1 : 1; | ||
| 250 | else | ||
| 251 | return 0; | ||
| 252 | } | ||
| 253 | if ((int64_t)x < 0) { | ||
| 254 | x = -x; | ||
| 255 | sign = (k & 1); | ||
| 256 | } | ||
| 257 | } | ||
| 258 | for (; (k & 1) == 0; k >>= 1) x *= x; | ||
| 259 | y = x; | ||
| 260 | if ((k >>= 1) != 0) { | ||
| 261 | for (;;) { | ||
| 262 | x *= x; | ||
| 263 | if (k == 1) break; | ||
| 264 | if (k & 1) y *= x; | ||
| 265 | k >>= 1; | ||
| 266 | } | ||
| 267 | y *= x; | ||
| 268 | } | ||
| 269 | if (sign) y = (uint64_t)-(int64_t)y; | ||
| 270 | return y; | ||
| 271 | } | ||
| 272 | |||
| 233 | #endif | 273 | #endif |
diff --git a/src/lj_cdata.h b/src/lj_cdata.h index 27b0bf15..5de82067 100644 --- a/src/lj_cdata.h +++ b/src/lj_cdata.h | |||
| @@ -66,6 +66,8 @@ LJ_FUNC void lj_cdata_get(CTState *cts, CType *s, TValue *o, uint8_t *sp); | |||
| 66 | LJ_FUNC void lj_cdata_set(CTState *cts, CType *d, uint8_t *dp, TValue *o, | 66 | LJ_FUNC void lj_cdata_set(CTState *cts, CType *d, uint8_t *dp, TValue *o, |
| 67 | CTInfo qual); | 67 | CTInfo qual); |
| 68 | 68 | ||
| 69 | LJ_FUNC uint64_t lj_cdata_powi64(uint64_t x, uint64_t k, int isunsigned); | ||
| 70 | |||
| 69 | #endif | 71 | #endif |
| 70 | 72 | ||
| 71 | #endif | 73 | #endif |
diff --git a/src/lj_errmsg.h b/src/lj_errmsg.h index 1075a9b4..66062747 100644 --- a/src/lj_errmsg.h +++ b/src/lj_errmsg.h | |||
| @@ -147,6 +147,7 @@ ERRDEF(FFI_BADTAG, "undeclared or implicit tag " LUA_QS) | |||
| 147 | ERRDEF(FFI_REDEF, "attempt to redefine " LUA_QS) | 147 | ERRDEF(FFI_REDEF, "attempt to redefine " LUA_QS) |
| 148 | ERRDEF(FFI_INITOV, "too many initializers for " LUA_QS) | 148 | ERRDEF(FFI_INITOV, "too many initializers for " LUA_QS) |
| 149 | ERRDEF(FFI_BADCONV, "cannot convert " LUA_QS " to " LUA_QS) | 149 | ERRDEF(FFI_BADCONV, "cannot convert " LUA_QS " to " LUA_QS) |
| 150 | ERRDEF(FFI_BADARITH, "attempt to perform arithmetic on " LUA_QS " and " LUA_QS) | ||
| 150 | ERRDEF(FFI_BADMEMBER, LUA_QS " has no member named " LUA_QS) | 151 | ERRDEF(FFI_BADMEMBER, LUA_QS " has no member named " LUA_QS) |
| 151 | ERRDEF(FFI_BADIDX, LUA_QS " cannot be indexed") | 152 | ERRDEF(FFI_BADIDX, LUA_QS " cannot be indexed") |
| 152 | ERRDEF(FFI_WRCONST, "attempt to write to constant location") | 153 | ERRDEF(FFI_WRCONST, "attempt to write to constant location") |
diff --git a/src/lj_obj.h b/src/lj_obj.h index 83e30b6e..d735b0e8 100644 --- a/src/lj_obj.h +++ b/src/lj_obj.h | |||
| @@ -738,6 +738,8 @@ define_setV(setudataV, GCudata, LJ_TUDATA) | |||
| 738 | 738 | ||
| 739 | #define setnumV(o, x) ((o)->n = (x)) | 739 | #define setnumV(o, x) ((o)->n = (x)) |
| 740 | #define setnanV(o) ((o)->u64 = U64x(fff80000,00000000)) | 740 | #define setnanV(o) ((o)->u64 = U64x(fff80000,00000000)) |
| 741 | #define setpinfV(o) ((o)->u64 = U64x(7ff00000,00000000)) | ||
| 742 | #define setminfV(o) ((o)->u64 = U64x(fff00000,00000000)) | ||
| 741 | #define setintV(o, i) ((o)->n = cast_num((int32_t)(i))) | 743 | #define setintV(o, i) ((o)->n = cast_num((int32_t)(i))) |
| 742 | 744 | ||
| 743 | /* Copy tagged values. */ | 745 | /* Copy tagged values. */ |
