1 | /* |
2 | ** Bit manipulation library. |
3 | ** Copyright (C) 2005-2021 Mike Pall. See Copyright Notice in luajit.h |
4 | */ |
5 | |
6 | #define lib_bit_c |
7 | #define LUA_LIB |
8 | |
9 | #include "lua.h" |
10 | #include "lauxlib.h" |
11 | #include "lualib.h" |
12 | |
13 | #include "lj_obj.h" |
14 | #include "lj_err.h" |
15 | #include "lj_buf.h" |
16 | #include "lj_strscan.h" |
17 | #include "lj_strfmt.h" |
18 | #if LJ_HASFFI |
19 | #include "lj_ctype.h" |
20 | #include "lj_cdata.h" |
21 | #include "lj_cconv.h" |
22 | #include "lj_carith.h" |
23 | #endif |
24 | #include "lj_ff.h" |
25 | #include "lj_lib.h" |
26 | |
27 | /* ------------------------------------------------------------------------ */ |
28 | |
29 | #define LJLIB_MODULE_bit |
30 | |
31 | #if LJ_HASFFI |
32 | static int bit_result64(lua_State *L, CTypeID id, uint64_t x) |
33 | { |
34 | GCcdata *cd = lj_cdata_new_(L, id, 8); |
35 | *(uint64_t *)cdataptr(cd) = x; |
36 | setcdataV(L, L->base-1-LJ_FR2, cd); |
37 | return FFH_RES(1); |
38 | } |
39 | #else |
40 | static int32_t bit_checkbit(lua_State *L, int narg) |
41 | { |
42 | TValue *o = L->base + narg-1; |
43 | if (!(o < L->top && lj_strscan_numberobj(o))) |
44 | lj_err_argt(L, narg, LUA_TNUMBER); |
45 | if (LJ_LIKELY(tvisint(o))) { |
46 | return intV(o); |
47 | } else { |
48 | int32_t i = lj_num2bit(numV(o)); |
49 | if (LJ_DUALNUM) setintV(o, i); |
50 | return i; |
51 | } |
52 | } |
53 | #endif |
54 | |
55 | LJLIB_ASM(bit_tobit) LJLIB_REC(bit_tobit) |
56 | { |
57 | #if LJ_HASFFI |
58 | CTypeID id = 0; |
59 | setintV(L->base-1-LJ_FR2, (int32_t)lj_carith_check64(L, 1, &id)); |
60 | return FFH_RES(1); |
61 | #else |
62 | lj_lib_checknumber(L, 1); |
63 | return FFH_RETRY; |
64 | #endif |
65 | } |
66 | |
67 | LJLIB_ASM(bit_bnot) LJLIB_REC(bit_unary IR_BNOT) |
68 | { |
69 | #if LJ_HASFFI |
70 | CTypeID id = 0; |
71 | uint64_t x = lj_carith_check64(L, 1, &id); |
72 | return id ? bit_result64(L, id, ~x) : FFH_RETRY; |
73 | #else |
74 | lj_lib_checknumber(L, 1); |
75 | return FFH_RETRY; |
76 | #endif |
77 | } |
78 | |
79 | LJLIB_ASM(bit_bswap) LJLIB_REC(bit_unary IR_BSWAP) |
80 | { |
81 | #if LJ_HASFFI |
82 | CTypeID id = 0; |
83 | uint64_t x = lj_carith_check64(L, 1, &id); |
84 | return id ? bit_result64(L, id, lj_bswap64(x)) : FFH_RETRY; |
85 | #else |
86 | lj_lib_checknumber(L, 1); |
87 | return FFH_RETRY; |
88 | #endif |
89 | } |
90 | |
91 | LJLIB_ASM(bit_lshift) LJLIB_REC(bit_shift IR_BSHL) |
92 | { |
93 | #if LJ_HASFFI |
94 | CTypeID id = 0, id2 = 0; |
95 | uint64_t x = lj_carith_check64(L, 1, &id); |
96 | int32_t sh = (int32_t)lj_carith_check64(L, 2, &id2); |
97 | if (id) { |
98 | x = lj_carith_shift64(x, sh, curr_func(L)->c.ffid - (int)FF_bit_lshift); |
99 | return bit_result64(L, id, x); |
100 | } |
101 | if (id2) setintV(L->base+1, sh); |
102 | return FFH_RETRY; |
103 | #else |
104 | lj_lib_checknumber(L, 1); |
105 | bit_checkbit(L, 2); |
106 | return FFH_RETRY; |
107 | #endif |
108 | } |
109 | LJLIB_ASM_(bit_rshift) LJLIB_REC(bit_shift IR_BSHR) |
110 | LJLIB_ASM_(bit_arshift) LJLIB_REC(bit_shift IR_BSAR) |
111 | LJLIB_ASM_(bit_rol) LJLIB_REC(bit_shift IR_BROL) |
112 | LJLIB_ASM_(bit_ror) LJLIB_REC(bit_shift IR_BROR) |
113 | |
114 | LJLIB_ASM(bit_band) LJLIB_REC(bit_nary IR_BAND) |
115 | { |
116 | #if LJ_HASFFI |
117 | CTypeID id = 0; |
118 | TValue *o = L->base, *top = L->top; |
119 | int i = 0; |
120 | do { lj_carith_check64(L, ++i, &id); } while (++o < top); |
121 | if (id) { |
122 | CTState *cts = ctype_cts(L); |
123 | CType *ct = ctype_get(cts, id); |
124 | int op = curr_func(L)->c.ffid - (int)FF_bit_bor; |
125 | uint64_t x, y = op >= 0 ? 0 : ~(uint64_t)0; |
126 | o = L->base; |
127 | do { |
128 | lj_cconv_ct_tv(cts, ct, (uint8_t *)&x, o, 0); |
129 | if (op < 0) y &= x; else if (op == 0) y |= x; else y ^= x; |
130 | } while (++o < top); |
131 | return bit_result64(L, id, y); |
132 | } |
133 | return FFH_RETRY; |
134 | #else |
135 | int i = 0; |
136 | do { lj_lib_checknumber(L, ++i); } while (L->base+i < L->top); |
137 | return FFH_RETRY; |
138 | #endif |
139 | } |
140 | LJLIB_ASM_(bit_bor) LJLIB_REC(bit_nary IR_BOR) |
141 | LJLIB_ASM_(bit_bxor) LJLIB_REC(bit_nary IR_BXOR) |
142 | |
143 | /* ------------------------------------------------------------------------ */ |
144 | |
145 | LJLIB_CF(bit_tohex) LJLIB_REC(.) |
146 | { |
147 | #if LJ_HASFFI |
148 | CTypeID id = 0, id2 = 0; |
149 | uint64_t b = lj_carith_check64(L, 1, &id); |
150 | int32_t n = L->base+1>=L->top ? (id ? 16 : 8) : |
151 | (int32_t)lj_carith_check64(L, 2, &id2); |
152 | #else |
153 | uint32_t b = (uint32_t)bit_checkbit(L, 1); |
154 | int32_t n = L->base+1>=L->top ? 8 : bit_checkbit(L, 2); |
155 | #endif |
156 | SBuf *sb = lj_buf_tmp_(L); |
157 | SFormat sf = (STRFMT_UINT|STRFMT_T_HEX); |
158 | if (n < 0) { n = -n; sf |= STRFMT_F_UPPER; } |
159 | sf |= ((SFormat)((n+1)&255) << STRFMT_SH_PREC); |
160 | #if LJ_HASFFI |
161 | if (n < 16) b &= ((uint64_t)1 << 4*n)-1; |
162 | #else |
163 | if (n < 8) b &= (1u << 4*n)-1; |
164 | #endif |
165 | sb = lj_strfmt_putfxint(sb, sf, b); |
166 | setstrV(L, L->top-1, lj_buf_str(L, sb)); |
167 | lj_gc_check(L); |
168 | return 1; |
169 | } |
170 | |
171 | /* ------------------------------------------------------------------------ */ |
172 | |
173 | #include "lj_libdef.h" |
174 | |
175 | LUALIB_API int luaopen_bit(lua_State *L) |
176 | { |
177 | LJ_LIB_REG(L, LUA_BITLIBNAME, bit); |
178 | return 1; |
179 | } |
180 | |
181 | |