diff options
Diffstat (limited to 'src')
-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, |