1 | /* |
2 | ** C data arithmetic. |
3 | ** Copyright (C) 2005-2021 Mike Pall. See Copyright Notice in luajit.h |
4 | */ |
5 | |
6 | #include "lj_obj.h" |
7 | |
8 | #if LJ_HASFFI |
9 | |
10 | #include "lj_gc.h" |
11 | #include "lj_err.h" |
12 | #include "lj_tab.h" |
13 | #include "lj_meta.h" |
14 | #include "lj_ir.h" |
15 | #include "lj_ctype.h" |
16 | #include "lj_cconv.h" |
17 | #include "lj_cdata.h" |
18 | #include "lj_carith.h" |
19 | #include "lj_strscan.h" |
20 | |
21 | /* -- C data arithmetic --------------------------------------------------- */ |
22 | |
23 | /* Binary operands of an operator converted to ctypes. */ |
24 | typedef struct CDArith { |
25 | uint8_t *p[2]; |
26 | CType *ct[2]; |
27 | } CDArith; |
28 | |
29 | /* Check arguments for arithmetic metamethods. */ |
30 | static int carith_checkarg(lua_State *L, CTState *cts, CDArith *ca) |
31 | { |
32 | TValue *o = L->base; |
33 | int ok = 1; |
34 | MSize i; |
35 | if (o+1 >= L->top) |
36 | lj_err_argt(L, 1, LUA_TCDATA); |
37 | for (i = 0; i < 2; i++, o++) { |
38 | if (tviscdata(o)) { |
39 | GCcdata *cd = cdataV(o); |
40 | CTypeID id = (CTypeID)cd->ctypeid; |
41 | CType *ct = ctype_raw(cts, id); |
42 | uint8_t *p = (uint8_t *)cdataptr(cd); |
43 | if (ctype_isptr(ct->info)) { |
44 | p = (uint8_t *)cdata_getptr(p, ct->size); |
45 | if (ctype_isref(ct->info)) ct = ctype_rawchild(cts, ct); |
46 | } else if (ctype_isfunc(ct->info)) { |
47 | p = (uint8_t *)*(void **)p; |
48 | ct = ctype_get(cts, |
49 | lj_ctype_intern(cts, CTINFO(CT_PTR, CTALIGN_PTR|id), CTSIZE_PTR)); |
50 | } |
51 | if (ctype_isenum(ct->info)) ct = ctype_child(cts, ct); |
52 | ca->ct[i] = ct; |
53 | ca->p[i] = p; |
54 | } else if (tvisint(o)) { |
55 | ca->ct[i] = ctype_get(cts, CTID_INT32); |
56 | ca->p[i] = (uint8_t *)&o->i; |
57 | } else if (tvisnum(o)) { |
58 | ca->ct[i] = ctype_get(cts, CTID_DOUBLE); |
59 | ca->p[i] = (uint8_t *)&o->n; |
60 | } else if (tvisnil(o)) { |
61 | ca->ct[i] = ctype_get(cts, CTID_P_VOID); |
62 | ca->p[i] = (uint8_t *)0; |
63 | } else if (tvisstr(o)) { |
64 | TValue *o2 = i == 0 ? o+1 : o-1; |
65 | CType *ct = ctype_raw(cts, cdataV(o2)->ctypeid); |
66 | ca->ct[i] = NULL; |
67 | ca->p[i] = (uint8_t *)strVdata(o); |
68 | ok = 0; |
69 | if (ctype_isenum(ct->info)) { |
70 | CTSize ofs; |
71 | CType *cct = lj_ctype_getfield(cts, ct, strV(o), &ofs); |
72 | if (cct && ctype_isconstval(cct->info)) { |
73 | ca->ct[i] = ctype_child(cts, cct); |
74 | ca->p[i] = (uint8_t *)&cct->size; /* Assumes ct does not grow. */ |
75 | ok = 1; |
76 | } else { |
77 | ca->ct[1-i] = ct; /* Use enum to improve error message. */ |
78 | ca->p[1-i] = NULL; |
79 | break; |
80 | } |
81 | } |
82 | } else { |
83 | ca->ct[i] = NULL; |
84 | ca->p[i] = (void *)(intptr_t)1; /* To make it unequal. */ |
85 | ok = 0; |
86 | } |
87 | } |
88 | return ok; |
89 | } |
90 | |
91 | /* Pointer arithmetic. */ |
92 | static int carith_ptr(lua_State *L, CTState *cts, CDArith *ca, MMS mm) |
93 | { |
94 | CType *ctp = ca->ct[0]; |
95 | uint8_t *pp = ca->p[0]; |
96 | ptrdiff_t idx; |
97 | CTSize sz; |
98 | CTypeID id; |
99 | GCcdata *cd; |
100 | if (ctype_isptr(ctp->info) || ctype_isrefarray(ctp->info)) { |
101 | if ((mm == MM_sub || mm == MM_eq || mm == MM_lt || mm == MM_le) && |
102 | (ctype_isptr(ca->ct[1]->info) || ctype_isrefarray(ca->ct[1]->info))) { |
103 | uint8_t *pp2 = ca->p[1]; |
104 | if (mm == MM_eq) { /* Pointer equality. Incompatible pointers are ok. */ |
105 | setboolV(L->top-1, (pp == pp2)); |
106 | return 1; |
107 | } |
108 | if (!lj_cconv_compatptr(cts, ctp, ca->ct[1], CCF_IGNQUAL)) |
109 | return 0; |
110 | if (mm == MM_sub) { /* Pointer difference. */ |
111 | intptr_t diff; |
112 | sz = lj_ctype_size(cts, ctype_cid(ctp->info)); /* Element size. */ |
113 | if (sz == 0 || sz == CTSIZE_INVALID) |
114 | return 0; |
115 | diff = ((intptr_t)pp - (intptr_t)pp2) / (int32_t)sz; |
116 | /* All valid pointer differences on x64 are in (-2^47, +2^47), |
117 | ** which fits into a double without loss of precision. |
118 | */ |
119 | setintptrV(L->top-1, (int32_t)diff); |
120 | return 1; |
121 | } else if (mm == MM_lt) { /* Pointer comparison (unsigned). */ |
122 | setboolV(L->top-1, ((uintptr_t)pp < (uintptr_t)pp2)); |
123 | return 1; |
124 | } else { |
125 | lj_assertL(mm == MM_le, "bad metamethod %d" , mm); |
126 | setboolV(L->top-1, ((uintptr_t)pp <= (uintptr_t)pp2)); |
127 | return 1; |
128 | } |
129 | } |
130 | if (!((mm == MM_add || mm == MM_sub) && ctype_isnum(ca->ct[1]->info))) |
131 | return 0; |
132 | lj_cconv_ct_ct(cts, ctype_get(cts, CTID_INT_PSZ), ca->ct[1], |
133 | (uint8_t *)&idx, ca->p[1], 0); |
134 | if (mm == MM_sub) idx = -idx; |
135 | } else if (mm == MM_add && ctype_isnum(ctp->info) && |
136 | (ctype_isptr(ca->ct[1]->info) || ctype_isrefarray(ca->ct[1]->info))) { |
137 | /* Swap pointer and index. */ |
138 | ctp = ca->ct[1]; pp = ca->p[1]; |
139 | lj_cconv_ct_ct(cts, ctype_get(cts, CTID_INT_PSZ), ca->ct[0], |
140 | (uint8_t *)&idx, ca->p[0], 0); |
141 | } else { |
142 | return 0; |
143 | } |
144 | sz = lj_ctype_size(cts, ctype_cid(ctp->info)); /* Element size. */ |
145 | if (sz == CTSIZE_INVALID) |
146 | return 0; |
147 | pp += idx*(int32_t)sz; /* Compute pointer + index. */ |
148 | id = lj_ctype_intern(cts, CTINFO(CT_PTR, CTALIGN_PTR|ctype_cid(ctp->info)), |
149 | CTSIZE_PTR); |
150 | cd = lj_cdata_new(cts, id, CTSIZE_PTR); |
151 | *(uint8_t **)cdataptr(cd) = pp; |
152 | setcdataV(L, L->top-1, cd); |
153 | lj_gc_check(L); |
154 | return 1; |
155 | } |
156 | |
157 | /* 64 bit integer arithmetic. */ |
158 | static int carith_int64(lua_State *L, CTState *cts, CDArith *ca, MMS mm) |
159 | { |
160 | if (ctype_isnum(ca->ct[0]->info) && ca->ct[0]->size <= 8 && |
161 | ctype_isnum(ca->ct[1]->info) && ca->ct[1]->size <= 8) { |
162 | CTypeID id = (((ca->ct[0]->info & CTF_UNSIGNED) && ca->ct[0]->size == 8) || |
163 | ((ca->ct[1]->info & CTF_UNSIGNED) && ca->ct[1]->size == 8)) ? |
164 | CTID_UINT64 : CTID_INT64; |
165 | CType *ct = ctype_get(cts, id); |
166 | GCcdata *cd; |
167 | uint64_t u0, u1, *up; |
168 | lj_cconv_ct_ct(cts, ct, ca->ct[0], (uint8_t *)&u0, ca->p[0], 0); |
169 | if (mm != MM_unm) |
170 | lj_cconv_ct_ct(cts, ct, ca->ct[1], (uint8_t *)&u1, ca->p[1], 0); |
171 | switch (mm) { |
172 | case MM_eq: |
173 | setboolV(L->top-1, (u0 == u1)); |
174 | return 1; |
175 | case MM_lt: |
176 | setboolV(L->top-1, |
177 | id == CTID_INT64 ? ((int64_t)u0 < (int64_t)u1) : (u0 < u1)); |
178 | return 1; |
179 | case MM_le: |
180 | setboolV(L->top-1, |
181 | id == CTID_INT64 ? ((int64_t)u0 <= (int64_t)u1) : (u0 <= u1)); |
182 | return 1; |
183 | default: break; |
184 | } |
185 | cd = lj_cdata_new(cts, id, 8); |
186 | up = (uint64_t *)cdataptr(cd); |
187 | setcdataV(L, L->top-1, cd); |
188 | switch (mm) { |
189 | case MM_add: *up = u0 + u1; break; |
190 | case MM_sub: *up = u0 - u1; break; |
191 | case MM_mul: *up = u0 * u1; break; |
192 | case MM_div: |
193 | if (id == CTID_INT64) |
194 | *up = (uint64_t)lj_carith_divi64((int64_t)u0, (int64_t)u1); |
195 | else |
196 | *up = lj_carith_divu64(u0, u1); |
197 | break; |
198 | case MM_mod: |
199 | if (id == CTID_INT64) |
200 | *up = (uint64_t)lj_carith_modi64((int64_t)u0, (int64_t)u1); |
201 | else |
202 | *up = lj_carith_modu64(u0, u1); |
203 | break; |
204 | case MM_pow: |
205 | if (id == CTID_INT64) |
206 | *up = (uint64_t)lj_carith_powi64((int64_t)u0, (int64_t)u1); |
207 | else |
208 | *up = lj_carith_powu64(u0, u1); |
209 | break; |
210 | case MM_unm: *up = (uint64_t)-(int64_t)u0; break; |
211 | default: |
212 | lj_assertL(0, "bad metamethod %d" , mm); |
213 | break; |
214 | } |
215 | lj_gc_check(L); |
216 | return 1; |
217 | } |
218 | return 0; |
219 | } |
220 | |
221 | /* Handle ctype arithmetic metamethods. */ |
222 | static int lj_carith_meta(lua_State *L, CTState *cts, CDArith *ca, MMS mm) |
223 | { |
224 | cTValue *tv = NULL; |
225 | if (tviscdata(L->base)) { |
226 | CTypeID id = cdataV(L->base)->ctypeid; |
227 | CType *ct = ctype_raw(cts, id); |
228 | if (ctype_isptr(ct->info)) id = ctype_cid(ct->info); |
229 | tv = lj_ctype_meta(cts, id, mm); |
230 | } |
231 | if (!tv && L->base+1 < L->top && tviscdata(L->base+1)) { |
232 | CTypeID id = cdataV(L->base+1)->ctypeid; |
233 | CType *ct = ctype_raw(cts, id); |
234 | if (ctype_isptr(ct->info)) id = ctype_cid(ct->info); |
235 | tv = lj_ctype_meta(cts, id, mm); |
236 | } |
237 | if (!tv) { |
238 | const char *repr[2]; |
239 | int i, isenum = -1, isstr = -1; |
240 | if (mm == MM_eq) { /* Equality checks never raise an error. */ |
241 | int eq = ca->p[0] == ca->p[1]; |
242 | setboolV(L->top-1, eq); |
243 | setboolV(&G(L)->tmptv2, eq); /* Remember for trace recorder. */ |
244 | return 1; |
245 | } |
246 | for (i = 0; i < 2; i++) { |
247 | if (ca->ct[i] && tviscdata(L->base+i)) { |
248 | if (ctype_isenum(ca->ct[i]->info)) isenum = i; |
249 | repr[i] = strdata(lj_ctype_repr(L, ctype_typeid(cts, ca->ct[i]), NULL)); |
250 | } else { |
251 | if (tvisstr(&L->base[i])) isstr = i; |
252 | repr[i] = lj_typename(&L->base[i]); |
253 | } |
254 | } |
255 | if ((isenum ^ isstr) == 1) |
256 | lj_err_callerv(L, LJ_ERR_FFI_BADCONV, repr[isstr], repr[isenum]); |
257 | lj_err_callerv(L, mm == MM_len ? LJ_ERR_FFI_BADLEN : |
258 | mm == MM_concat ? LJ_ERR_FFI_BADCONCAT : |
259 | mm < MM_add ? LJ_ERR_FFI_BADCOMP : LJ_ERR_FFI_BADARITH, |
260 | repr[0], repr[1]); |
261 | } |
262 | return lj_meta_tailcall(L, tv); |
263 | } |
264 | |
265 | /* Arithmetic operators for cdata. */ |
266 | int lj_carith_op(lua_State *L, MMS mm) |
267 | { |
268 | CTState *cts = ctype_cts(L); |
269 | CDArith ca; |
270 | if (carith_checkarg(L, cts, &ca) && mm != MM_len && mm != MM_concat) { |
271 | if (carith_int64(L, cts, &ca, mm) || carith_ptr(L, cts, &ca, mm)) { |
272 | copyTV(L, &G(L)->tmptv2, L->top-1); /* Remember for trace recorder. */ |
273 | return 1; |
274 | } |
275 | } |
276 | return lj_carith_meta(L, cts, &ca, mm); |
277 | } |
278 | |
279 | /* -- 64 bit bit operations helpers --------------------------------------- */ |
280 | |
281 | #if LJ_64 |
282 | #define B64DEF(name) \ |
283 | static LJ_AINLINE uint64_t lj_carith_##name(uint64_t x, int32_t sh) |
284 | #else |
285 | /* Not inlined on 32 bit archs, since some of these are quite lengthy. */ |
286 | #define B64DEF(name) \ |
287 | uint64_t LJ_NOINLINE lj_carith_##name(uint64_t x, int32_t sh) |
288 | #endif |
289 | |
290 | B64DEF(shl64) { return x << (sh&63); } |
291 | B64DEF(shr64) { return x >> (sh&63); } |
292 | B64DEF(sar64) { return (uint64_t)((int64_t)x >> (sh&63)); } |
293 | B64DEF(rol64) { return lj_rol(x, (sh&63)); } |
294 | B64DEF(ror64) { return lj_ror(x, (sh&63)); } |
295 | |
296 | #undef B64DEF |
297 | |
298 | uint64_t lj_carith_shift64(uint64_t x, int32_t sh, int op) |
299 | { |
300 | switch (op) { |
301 | case IR_BSHL-IR_BSHL: x = lj_carith_shl64(x, sh); break; |
302 | case IR_BSHR-IR_BSHL: x = lj_carith_shr64(x, sh); break; |
303 | case IR_BSAR-IR_BSHL: x = lj_carith_sar64(x, sh); break; |
304 | case IR_BROL-IR_BSHL: x = lj_carith_rol64(x, sh); break; |
305 | case IR_BROR-IR_BSHL: x = lj_carith_ror64(x, sh); break; |
306 | default: |
307 | lj_assertX(0, "bad shift op %d" , op); |
308 | break; |
309 | } |
310 | return x; |
311 | } |
312 | |
313 | /* Equivalent to lj_lib_checkbit(), but handles cdata. */ |
314 | uint64_t lj_carith_check64(lua_State *L, int narg, CTypeID *id) |
315 | { |
316 | TValue *o = L->base + narg-1; |
317 | if (o >= L->top) { |
318 | err: |
319 | lj_err_argt(L, narg, LUA_TNUMBER); |
320 | } else if (LJ_LIKELY(tvisnumber(o))) { |
321 | /* Handled below. */ |
322 | } else if (tviscdata(o)) { |
323 | CTState *cts = ctype_cts(L); |
324 | uint8_t *sp = (uint8_t *)cdataptr(cdataV(o)); |
325 | CTypeID sid = cdataV(o)->ctypeid; |
326 | CType *s = ctype_get(cts, sid); |
327 | uint64_t x; |
328 | if (ctype_isref(s->info)) { |
329 | sp = *(void **)sp; |
330 | sid = ctype_cid(s->info); |
331 | } |
332 | s = ctype_raw(cts, sid); |
333 | if (ctype_isenum(s->info)) s = ctype_child(cts, s); |
334 | if ((s->info & (CTMASK_NUM|CTF_BOOL|CTF_FP|CTF_UNSIGNED)) == |
335 | CTINFO(CT_NUM, CTF_UNSIGNED) && s->size == 8) |
336 | *id = CTID_UINT64; /* Use uint64_t, since it has the highest rank. */ |
337 | else if (!*id) |
338 | *id = CTID_INT64; /* Use int64_t, unless already set. */ |
339 | lj_cconv_ct_ct(cts, ctype_get(cts, *id), s, |
340 | (uint8_t *)&x, sp, CCF_ARG(narg)); |
341 | return x; |
342 | } else if (!(tvisstr(o) && lj_strscan_number(strV(o), o))) { |
343 | goto err; |
344 | } |
345 | if (LJ_LIKELY(tvisint(o))) { |
346 | return (uint32_t)intV(o); |
347 | } else { |
348 | int32_t i = lj_num2bit(numV(o)); |
349 | if (LJ_DUALNUM) setintV(o, i); |
350 | return (uint32_t)i; |
351 | } |
352 | } |
353 | |
354 | /* -- 64 bit integer arithmetic helpers ----------------------------------- */ |
355 | |
356 | #if LJ_32 && LJ_HASJIT |
357 | /* Signed/unsigned 64 bit multiplication. */ |
358 | int64_t lj_carith_mul64(int64_t a, int64_t b) |
359 | { |
360 | return a * b; |
361 | } |
362 | #endif |
363 | |
364 | /* Unsigned 64 bit division. */ |
365 | uint64_t lj_carith_divu64(uint64_t a, uint64_t b) |
366 | { |
367 | if (b == 0) return U64x(80000000,00000000); |
368 | return a / b; |
369 | } |
370 | |
371 | /* Signed 64 bit division. */ |
372 | int64_t lj_carith_divi64(int64_t a, int64_t b) |
373 | { |
374 | if (b == 0 || (a == (int64_t)U64x(80000000,00000000) && b == -1)) |
375 | return U64x(80000000,00000000); |
376 | return a / b; |
377 | } |
378 | |
379 | /* Unsigned 64 bit modulo. */ |
380 | uint64_t lj_carith_modu64(uint64_t a, uint64_t b) |
381 | { |
382 | if (b == 0) return U64x(80000000,00000000); |
383 | return a % b; |
384 | } |
385 | |
386 | /* Signed 64 bit modulo. */ |
387 | int64_t lj_carith_modi64(int64_t a, int64_t b) |
388 | { |
389 | if (b == 0) return U64x(80000000,00000000); |
390 | if (a == (int64_t)U64x(80000000,00000000) && b == -1) return 0; |
391 | return a % b; |
392 | } |
393 | |
394 | /* Unsigned 64 bit x^k. */ |
395 | uint64_t lj_carith_powu64(uint64_t x, uint64_t k) |
396 | { |
397 | uint64_t y; |
398 | if (k == 0) |
399 | return 1; |
400 | for (; (k & 1) == 0; k >>= 1) x *= x; |
401 | y = x; |
402 | if ((k >>= 1) != 0) { |
403 | for (;;) { |
404 | x *= x; |
405 | if (k == 1) break; |
406 | if (k & 1) y *= x; |
407 | k >>= 1; |
408 | } |
409 | y *= x; |
410 | } |
411 | return y; |
412 | } |
413 | |
414 | /* Signed 64 bit x^k. */ |
415 | int64_t lj_carith_powi64(int64_t x, int64_t k) |
416 | { |
417 | if (k == 0) |
418 | return 1; |
419 | if (k < 0) { |
420 | if (x == 0) |
421 | return U64x(7fffffff,ffffffff); |
422 | else if (x == 1) |
423 | return 1; |
424 | else if (x == -1) |
425 | return (k & 1) ? -1 : 1; |
426 | else |
427 | return 0; |
428 | } |
429 | return (int64_t)lj_carith_powu64((uint64_t)x, (uint64_t)k); |
430 | } |
431 | |
432 | #endif |
433 | |