diff options
Diffstat (limited to 'src/lib_ffi.c')
-rw-r--r-- | src/lib_ffi.c | 110 |
1 files changed, 110 insertions, 0 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); |