diff options
| -rw-r--r-- | src/lib_ffi.c | 110 | ||||
| -rw-r--r-- | src/lj_cconv.c | 12 | ||||
| -rw-r--r-- | src/lj_cconv.h | 2 |
3 files changed, 118 insertions, 6 deletions
diff --git a/src/lib_ffi.c b/src/lib_ffi.c index e7108c59..ed73a5fe 100644 --- a/src/lib_ffi.c +++ b/src/lib_ffi.c | |||
| @@ -74,6 +74,41 @@ static void *ffi_checkptr(lua_State *L, int narg, CTypeID id) | |||
| 74 | return p; | 74 | return p; |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | typedef struct FFIArith { | ||
| 78 | uint8_t *p[2]; | ||
| 79 | CType *ct[2]; | ||
| 80 | } FFIArith; | ||
| 81 | |||
| 82 | /* Check arguments for arithmetic metamethods. */ | ||
| 83 | static void ffi_checkarith(lua_State *L, FFIArith *fa) | ||
| 84 | { | ||
| 85 | CTState *cts = ctype_cts(L); | ||
| 86 | TValue *o = L->base; | ||
| 87 | MSize i; | ||
| 88 | if (o+1 >= L->top) | ||
| 89 | lj_err_argt(L, 1, LUA_TCDATA); | ||
| 90 | for (i = 0; i < 2; i++, o++) { | ||
| 91 | if (tviscdata(o)) { | ||
| 92 | GCcdata *cd = cdataV(o); | ||
| 93 | CTypeID id = (CTypeID)cd->typeid; | ||
| 94 | CType *ct = ctype_get(cts, id); | ||
| 95 | uint8_t *p = (uint8_t *)cdataptr(cd); | ||
| 96 | if (ctype_isref(ct->info)) { | ||
| 97 | lua_assert(ct->size == CTSIZE_PTR); | ||
| 98 | p = *(uint8_t **)p; | ||
| 99 | id = ctype_cid(ct->info); | ||
| 100 | } | ||
| 101 | fa->ct[i] = ctype_raw(cts, id); | ||
| 102 | fa->p[i] = p; | ||
| 103 | } else if (tvisnum(o)) { | ||
| 104 | fa->ct[i] = ctype_get(cts, CTID_DOUBLE); | ||
| 105 | fa->p[i] = (uint8_t *)&o->n; | ||
| 106 | } else { | ||
| 107 | lj_err_optype(L, o, LJ_ERR_OPARITH); | ||
| 108 | } | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 77 | /* -- C type metamethods -------------------------------------------------- */ | 112 | /* -- C type metamethods -------------------------------------------------- */ |
| 78 | 113 | ||
| 79 | #define LJLIB_MODULE_ffi_meta | 114 | #define LJLIB_MODULE_ffi_meta |
| @@ -118,6 +153,81 @@ LJLIB_CF(ffi_meta___call) LJLIB_REC(cdata_call) | |||
| 118 | return 0; /* unreachable */ | 153 | return 0; /* unreachable */ |
| 119 | } | 154 | } |
| 120 | 155 | ||
| 156 | /* Pointer arithmetic. */ | ||
| 157 | static int ffi_arith_ptr(lua_State *L, FFIArith *fa, int sub) | ||
| 158 | { | ||
| 159 | CTState *cts = ctype_cts(L); | ||
| 160 | CType *ctp = fa->ct[0]; | ||
| 161 | uint8_t *pp = fa->p[0]; | ||
| 162 | ptrdiff_t idx; | ||
| 163 | CTSize sz; | ||
| 164 | CTypeID id; | ||
| 165 | GCcdata *cd; | ||
| 166 | if (ctype_isptr(ctp->info) || ctype_isrefarray(ctp->info)) { | ||
| 167 | if (sub && | ||
| 168 | (ctype_isptr(fa->ct[1]->info) || ctype_isrefarray(fa->ct[1]->info))) { | ||
| 169 | /* Pointer difference. */ | ||
| 170 | intptr_t diff; | ||
| 171 | if (!lj_cconv_compatptr(cts, ctp, fa->ct[1], CCF_IGNQUAL)) | ||
| 172 | lj_err_caller(L, LJ_ERR_FFI_INVTYPE); | ||
| 173 | sz = lj_ctype_size(cts, ctype_cid(ctp->info)); /* Element size. */ | ||
| 174 | if (sz == 0 || sz == CTSIZE_INVALID) | ||
| 175 | lj_err_caller(L, LJ_ERR_FFI_INVSIZE); | ||
| 176 | if (ctype_isptr(ctp->info)) | ||
| 177 | pp = (uint8_t *)cdata_getptr(pp, ctp->size); | ||
| 178 | if (ctype_isptr(fa->ct[1]->info)) | ||
| 179 | fa->p[1] = (uint8_t *)cdata_getptr(fa->p[1], fa->ct[1]->size); | ||
| 180 | diff = ((intptr_t)pp - (intptr_t)fa->p[1]) / (int32_t)sz; | ||
| 181 | /* All valid pointer differences on x64 are in (-2^47, +2^47), | ||
| 182 | ** which fits into a double without loss of precision. | ||
| 183 | */ | ||
| 184 | setnumV(L->top-1, (lua_Number)diff); | ||
| 185 | return 1; | ||
| 186 | } | ||
| 187 | lj_cconv_ct_ct(cts, ctype_get(cts, CTID_INT_PSZ), fa->ct[1], | ||
| 188 | (uint8_t *)&idx, fa->p[1], 0); | ||
| 189 | if (sub) idx = -idx; | ||
| 190 | } else if (!sub && | ||
| 191 | (ctype_isptr(fa->ct[1]->info) || ctype_isrefarray(fa->ct[1]->info))) { | ||
| 192 | /* Swap pointer and index. */ | ||
| 193 | ctp = fa->ct[1]; pp = fa->p[1]; | ||
| 194 | lj_cconv_ct_ct(cts, ctype_get(cts, CTID_INT_PSZ), fa->ct[0], | ||
| 195 | (uint8_t *)&idx, fa->p[0], 0); | ||
| 196 | } else { | ||
| 197 | return 0; | ||
| 198 | } | ||
| 199 | sz = lj_ctype_size(cts, ctype_cid(ctp->info)); /* Element size. */ | ||
| 200 | if (sz == CTSIZE_INVALID) | ||
| 201 | lj_err_caller(L, LJ_ERR_FFI_INVSIZE); | ||
| 202 | if (ctype_isptr(ctp->info)) | ||
| 203 | pp = (uint8_t *)cdata_getptr(pp, ctp->size); | ||
| 204 | pp += idx*(int32_t)sz; /* Compute pointer + index. */ | ||
| 205 | id = lj_ctype_intern(cts, CTINFO(CT_PTR, CTALIGN_PTR|ctype_cid(ctp->info)), | ||
| 206 | CTSIZE_PTR); | ||
| 207 | cd = lj_cdata_new(cts, id, CTSIZE_PTR); | ||
| 208 | *(uint8_t **)cdataptr(cd) = pp; | ||
| 209 | setcdataV(L, L->top-1, cd); | ||
| 210 | return 1; | ||
| 211 | } | ||
| 212 | |||
| 213 | LJLIB_CF(ffi_meta___add) | ||
| 214 | { | ||
| 215 | FFIArith fa; | ||
| 216 | ffi_checkarith(L, &fa); | ||
| 217 | if (!ffi_arith_ptr(L, &fa, 0)) | ||
| 218 | lj_err_caller(L, LJ_ERR_FFI_INVTYPE); | ||
| 219 | return 1; | ||
| 220 | } | ||
| 221 | |||
| 222 | LJLIB_CF(ffi_meta___sub) | ||
| 223 | { | ||
| 224 | FFIArith fa; | ||
| 225 | ffi_checkarith(L, &fa); | ||
| 226 | if (!ffi_arith_ptr(L, &fa, 1)) | ||
| 227 | lj_err_caller(L, LJ_ERR_FFI_INVTYPE); | ||
| 228 | return 1; | ||
| 229 | } | ||
| 230 | |||
| 121 | LJLIB_CF(ffi_meta___tostring) | 231 | LJLIB_CF(ffi_meta___tostring) |
| 122 | { | 232 | { |
| 123 | GCcdata *cd = ffi_checkcdata(L, 1); | 233 | GCcdata *cd = ffi_checkcdata(L, 1); |
diff --git a/src/lj_cconv.c b/src/lj_cconv.c index 85fd57e5..e5abf3e9 100644 --- a/src/lj_cconv.c +++ b/src/lj_cconv.c | |||
| @@ -63,7 +63,7 @@ static CType *cconv_childqual(CTState *cts, CType *ct, CTInfo *qual) | |||
| 63 | /* Check for compatible types when converting to a pointer. | 63 | /* Check for compatible types when converting to a pointer. |
| 64 | ** Note: these checks are more relaxed than what C99 mandates. | 64 | ** Note: these checks are more relaxed than what C99 mandates. |
| 65 | */ | 65 | */ |
| 66 | static int cconv_compatptr(CTState *cts, CType *d, CType *s, CTInfo flags) | 66 | int lj_cconv_compatptr(CTState *cts, CType *d, CType *s, CTInfo flags) |
| 67 | { | 67 | { |
| 68 | if (!((flags & CCF_CAST) || d == s)) { | 68 | if (!((flags & CCF_CAST) || d == s)) { |
| 69 | CTInfo dqual = 0, squal = 0; | 69 | CTInfo dqual = 0, squal = 0; |
| @@ -73,7 +73,7 @@ static int cconv_compatptr(CTState *cts, CType *d, CType *s, CTInfo flags) | |||
| 73 | if ((flags & CCF_SAME)) { | 73 | if ((flags & CCF_SAME)) { |
| 74 | if (dqual != squal) | 74 | if (dqual != squal) |
| 75 | return 0; /* Different qualifiers. */ | 75 | return 0; /* Different qualifiers. */ |
| 76 | } else { | 76 | } else if (!(flags & CCF_IGNQUAL)) { |
| 77 | if ((dqual & squal) != squal) | 77 | if ((dqual & squal) != squal) |
| 78 | return 0; /* Discarded qualifiers. */ | 78 | return 0; /* Discarded qualifiers. */ |
| 79 | if (ctype_isvoid(d->info) || ctype_isvoid(s->info)) | 79 | if (ctype_isvoid(d->info) || ctype_isvoid(s->info)) |
| @@ -87,7 +87,7 @@ static int cconv_compatptr(CTState *cts, CType *d, CType *s, CTInfo flags) | |||
| 87 | return 0; /* Different numeric types. */ | 87 | return 0; /* Different numeric types. */ |
| 88 | } else if (ctype_ispointer(d->info)) { | 88 | } else if (ctype_ispointer(d->info)) { |
| 89 | /* Check child types for compatibility. */ | 89 | /* Check child types for compatibility. */ |
| 90 | return cconv_compatptr(cts, d, s, flags|CCF_SAME); | 90 | return lj_cconv_compatptr(cts, d, s, flags|CCF_SAME); |
| 91 | } else if (ctype_isstruct(d->info)) { | 91 | } else if (ctype_isstruct(d->info)) { |
| 92 | if (d != s) | 92 | if (d != s) |
| 93 | return 0; /* Must be exact same type for struct/union. */ | 93 | return 0; /* Must be exact same type for struct/union. */ |
| @@ -339,20 +339,20 @@ void lj_cconv_ct_ct(CTState *cts, CType *d, CType *s, | |||
| 339 | goto conv_I_F; | 339 | goto conv_I_F; |
| 340 | 340 | ||
| 341 | case CCX(P, P): | 341 | case CCX(P, P): |
| 342 | if (!cconv_compatptr(cts, d, s, flags)) goto err_conv; | 342 | if (!lj_cconv_compatptr(cts, d, s, flags)) goto err_conv; |
| 343 | cdata_setptr(dp, dsize, cdata_getptr(sp, ssize)); | 343 | cdata_setptr(dp, dsize, cdata_getptr(sp, ssize)); |
| 344 | break; | 344 | break; |
| 345 | 345 | ||
| 346 | case CCX(P, A): | 346 | case CCX(P, A): |
| 347 | case CCX(P, S): | 347 | case CCX(P, S): |
| 348 | if (!cconv_compatptr(cts, d, s, flags)) goto err_conv; | 348 | if (!lj_cconv_compatptr(cts, d, s, flags)) goto err_conv; |
| 349 | cdata_setptr(dp, dsize, sp); | 349 | cdata_setptr(dp, dsize, sp); |
| 350 | break; | 350 | break; |
| 351 | 351 | ||
| 352 | /* Destination is an array. */ | 352 | /* Destination is an array. */ |
| 353 | case CCX(A, A): | 353 | case CCX(A, A): |
| 354 | if ((flags & CCF_CAST) || (d->info & CTF_VLA) || d->size != s->size || | 354 | if ((flags & CCF_CAST) || (d->info & CTF_VLA) || d->size != s->size || |
| 355 | d->size == CTSIZE_INVALID || !cconv_compatptr(cts, d, s, flags)) | 355 | d->size == CTSIZE_INVALID || !lj_cconv_compatptr(cts, d, s, flags)) |
| 356 | goto err_conv; | 356 | goto err_conv; |
| 357 | goto copyval; | 357 | goto copyval; |
| 358 | 358 | ||
diff --git a/src/lj_cconv.h b/src/lj_cconv.h index 140ce8d6..dd2f2c40 100644 --- a/src/lj_cconv.h +++ b/src/lj_cconv.h | |||
| @@ -46,8 +46,10 @@ static LJ_AINLINE uint32_t cconv_idx(CTInfo info) | |||
| 46 | #define CCF_CAST 0x00000001u | 46 | #define CCF_CAST 0x00000001u |
| 47 | #define CCF_FROMTV 0x00000002u | 47 | #define CCF_FROMTV 0x00000002u |
| 48 | #define CCF_SAME 0x00000004u | 48 | #define CCF_SAME 0x00000004u |
| 49 | #define CCF_IGNQUAL 0x00000008u | ||
| 49 | 50 | ||
| 50 | 51 | ||
| 52 | LJ_FUNC int lj_cconv_compatptr(CTState *cts, CType *d, CType *s, CTInfo flags); | ||
| 51 | LJ_FUNC void lj_cconv_ct_ct(CTState *cts, CType *d, CType *s, | 53 | LJ_FUNC void lj_cconv_ct_ct(CTState *cts, CType *d, CType *s, |
| 52 | uint8_t *dp, uint8_t *sp, CTInfo flags); | 54 | uint8_t *dp, uint8_t *sp, CTInfo flags); |
| 53 | LJ_FUNC void lj_cconv_tv_ct(CTState *cts, CType *s, CTypeID sid, | 55 | LJ_FUNC void lj_cconv_tv_ct(CTState *cts, CType *s, CTypeID sid, |
