17d8dd8d9SRob Norris // SPDX-License-Identifier: MIT
2d99a0153SChris Williamson /*
3d99a0153SChris Williamson ** $Id: lcode.c,v 2.62.1.1 2013/04/12 18:48:47 roberto Exp $
4d99a0153SChris Williamson ** Code generator for Lua
5d99a0153SChris Williamson ** See Copyright Notice in lua.h
6d99a0153SChris Williamson */
7d99a0153SChris Williamson
8d99a0153SChris Williamson #define lcode_c
9d99a0153SChris Williamson #define LUA_CORE
10d99a0153SChris Williamson
116954c22fSBrian Behlendorf #if defined(HAVE_IMPLICIT_FALLTHROUGH)
126954c22fSBrian Behlendorf #pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
136954c22fSBrian Behlendorf #endif
146954c22fSBrian Behlendorf
15d99a0153SChris Williamson #include <sys/lua/lua.h>
16d99a0153SChris Williamson
17d99a0153SChris Williamson #include "lcode.h"
18d99a0153SChris Williamson #include "ldebug.h"
19d99a0153SChris Williamson #include "ldo.h"
20d99a0153SChris Williamson #include "lgc.h"
21d99a0153SChris Williamson #include "llex.h"
22d99a0153SChris Williamson #include "lmem.h"
23d99a0153SChris Williamson #include "lobject.h"
24d99a0153SChris Williamson #include "lopcodes.h"
25d99a0153SChris Williamson #include "lparser.h"
26d99a0153SChris Williamson #include "lstring.h"
27d99a0153SChris Williamson #include "ltable.h"
28d99a0153SChris Williamson #include "lvm.h"
29d99a0153SChris Williamson
30d99a0153SChris Williamson
31d99a0153SChris Williamson #define hasjumps(e) ((e)->t != (e)->f)
32d99a0153SChris Williamson
33d99a0153SChris Williamson
isnumeral(expdesc * e)34d99a0153SChris Williamson static int isnumeral(expdesc *e) {
35d99a0153SChris Williamson return (e->k == VKNUM && e->t == NO_JUMP && e->f == NO_JUMP);
36d99a0153SChris Williamson }
37d99a0153SChris Williamson
38d99a0153SChris Williamson
luaK_nil(FuncState * fs,int from,int n)39d99a0153SChris Williamson void luaK_nil (FuncState *fs, int from, int n) {
40d99a0153SChris Williamson Instruction *previous;
41d99a0153SChris Williamson int l = from + n - 1; /* last register to set nil */
42d99a0153SChris Williamson if (fs->pc > fs->lasttarget) { /* no jumps to current position? */
43d99a0153SChris Williamson previous = &fs->f->code[fs->pc-1];
44d99a0153SChris Williamson if (GET_OPCODE(*previous) == OP_LOADNIL) {
45d99a0153SChris Williamson int pfrom = GETARG_A(*previous);
46d99a0153SChris Williamson int pl = pfrom + GETARG_B(*previous);
47d99a0153SChris Williamson if ((pfrom <= from && from <= pl + 1) ||
48d99a0153SChris Williamson (from <= pfrom && pfrom <= l + 1)) { /* can connect both? */
49d99a0153SChris Williamson if (pfrom < from) from = pfrom; /* from = min(from, pfrom) */
50d99a0153SChris Williamson if (pl > l) l = pl; /* l = max(l, pl) */
51d99a0153SChris Williamson SETARG_A(*previous, from);
52d99a0153SChris Williamson SETARG_B(*previous, l - from);
53d99a0153SChris Williamson return;
54d99a0153SChris Williamson }
55d99a0153SChris Williamson } /* else go through */
56d99a0153SChris Williamson }
57d99a0153SChris Williamson luaK_codeABC(fs, OP_LOADNIL, from, n - 1, 0); /* else no optimization */
58d99a0153SChris Williamson }
59d99a0153SChris Williamson
60d99a0153SChris Williamson
luaK_jump(FuncState * fs)61d99a0153SChris Williamson int luaK_jump (FuncState *fs) {
62d99a0153SChris Williamson int jpc = fs->jpc; /* save list of jumps to here */
63d99a0153SChris Williamson int j;
64d99a0153SChris Williamson fs->jpc = NO_JUMP;
65d99a0153SChris Williamson j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP);
66d99a0153SChris Williamson luaK_concat(fs, &j, jpc); /* keep them on hold */
67d99a0153SChris Williamson return j;
68d99a0153SChris Williamson }
69d99a0153SChris Williamson
70d99a0153SChris Williamson
luaK_ret(FuncState * fs,int first,int nret)71d99a0153SChris Williamson void luaK_ret (FuncState *fs, int first, int nret) {
72d99a0153SChris Williamson luaK_codeABC(fs, OP_RETURN, first, nret+1, 0);
73d99a0153SChris Williamson }
74d99a0153SChris Williamson
75d99a0153SChris Williamson
condjump(FuncState * fs,OpCode op,int A,int B,int C)76d99a0153SChris Williamson static int condjump (FuncState *fs, OpCode op, int A, int B, int C) {
77d99a0153SChris Williamson luaK_codeABC(fs, op, A, B, C);
78d99a0153SChris Williamson return luaK_jump(fs);
79d99a0153SChris Williamson }
80d99a0153SChris Williamson
81d99a0153SChris Williamson
fixjump(FuncState * fs,int pc,int dest)82d99a0153SChris Williamson static void fixjump (FuncState *fs, int pc, int dest) {
83d99a0153SChris Williamson Instruction *jmp = &fs->f->code[pc];
84d99a0153SChris Williamson int offset = dest-(pc+1);
85d99a0153SChris Williamson lua_assert(dest != NO_JUMP);
86d99a0153SChris Williamson if (abs(offset) > MAXARG_sBx)
87d99a0153SChris Williamson luaX_syntaxerror(fs->ls, "control structure too long");
88d99a0153SChris Williamson SETARG_sBx(*jmp, offset);
89d99a0153SChris Williamson }
90d99a0153SChris Williamson
91d99a0153SChris Williamson
92d99a0153SChris Williamson /*
93d99a0153SChris Williamson ** returns current `pc' and marks it as a jump target (to avoid wrong
94d99a0153SChris Williamson ** optimizations with consecutive instructions not in the same basic block).
95d99a0153SChris Williamson */
luaK_getlabel(FuncState * fs)96d99a0153SChris Williamson int luaK_getlabel (FuncState *fs) {
97d99a0153SChris Williamson fs->lasttarget = fs->pc;
98d99a0153SChris Williamson return fs->pc;
99d99a0153SChris Williamson }
100d99a0153SChris Williamson
101d99a0153SChris Williamson
getjump(FuncState * fs,int pc)102d99a0153SChris Williamson static int getjump (FuncState *fs, int pc) {
103d99a0153SChris Williamson int offset = GETARG_sBx(fs->f->code[pc]);
104d99a0153SChris Williamson if (offset == NO_JUMP) /* point to itself represents end of list */
105d99a0153SChris Williamson return NO_JUMP; /* end of list */
106d99a0153SChris Williamson else
107d99a0153SChris Williamson return (pc+1)+offset; /* turn offset into absolute position */
108d99a0153SChris Williamson }
109d99a0153SChris Williamson
110d99a0153SChris Williamson
getjumpcontrol(FuncState * fs,int pc)111d99a0153SChris Williamson static Instruction *getjumpcontrol (FuncState *fs, int pc) {
112d99a0153SChris Williamson Instruction *pi = &fs->f->code[pc];
113d99a0153SChris Williamson if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1))))
114d99a0153SChris Williamson return pi-1;
115d99a0153SChris Williamson else
116d99a0153SChris Williamson return pi;
117d99a0153SChris Williamson }
118d99a0153SChris Williamson
119d99a0153SChris Williamson
120d99a0153SChris Williamson /*
121d99a0153SChris Williamson ** check whether list has any jump that do not produce a value
122d99a0153SChris Williamson ** (or produce an inverted value)
123d99a0153SChris Williamson */
need_value(FuncState * fs,int list)124d99a0153SChris Williamson static int need_value (FuncState *fs, int list) {
125d99a0153SChris Williamson for (; list != NO_JUMP; list = getjump(fs, list)) {
126d99a0153SChris Williamson Instruction i = *getjumpcontrol(fs, list);
127d99a0153SChris Williamson if (GET_OPCODE(i) != OP_TESTSET) return 1;
128d99a0153SChris Williamson }
129d99a0153SChris Williamson return 0; /* not found */
130d99a0153SChris Williamson }
131d99a0153SChris Williamson
132d99a0153SChris Williamson
patchtestreg(FuncState * fs,int node,int reg)133d99a0153SChris Williamson static int patchtestreg (FuncState *fs, int node, int reg) {
134d99a0153SChris Williamson Instruction *i = getjumpcontrol(fs, node);
135d99a0153SChris Williamson if (GET_OPCODE(*i) != OP_TESTSET)
136d99a0153SChris Williamson return 0; /* cannot patch other instructions */
137d99a0153SChris Williamson if (reg != NO_REG && reg != GETARG_B(*i))
138d99a0153SChris Williamson SETARG_A(*i, reg);
139d99a0153SChris Williamson else /* no register to put value or register already has the value */
140d99a0153SChris Williamson *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i));
141d99a0153SChris Williamson
142d99a0153SChris Williamson return 1;
143d99a0153SChris Williamson }
144d99a0153SChris Williamson
145d99a0153SChris Williamson
removevalues(FuncState * fs,int list)146d99a0153SChris Williamson static void removevalues (FuncState *fs, int list) {
147d99a0153SChris Williamson for (; list != NO_JUMP; list = getjump(fs, list))
148d99a0153SChris Williamson patchtestreg(fs, list, NO_REG);
149d99a0153SChris Williamson }
150d99a0153SChris Williamson
151d99a0153SChris Williamson
patchlistaux(FuncState * fs,int list,int vtarget,int reg,int dtarget)152d99a0153SChris Williamson static void patchlistaux (FuncState *fs, int list, int vtarget, int reg,
153d99a0153SChris Williamson int dtarget) {
154d99a0153SChris Williamson while (list != NO_JUMP) {
155d99a0153SChris Williamson int next = getjump(fs, list);
156d99a0153SChris Williamson if (patchtestreg(fs, list, reg))
157d99a0153SChris Williamson fixjump(fs, list, vtarget);
158d99a0153SChris Williamson else
159d99a0153SChris Williamson fixjump(fs, list, dtarget); /* jump to default target */
160d99a0153SChris Williamson list = next;
161d99a0153SChris Williamson }
162d99a0153SChris Williamson }
163d99a0153SChris Williamson
164d99a0153SChris Williamson
dischargejpc(FuncState * fs)165d99a0153SChris Williamson static void dischargejpc (FuncState *fs) {
166d99a0153SChris Williamson patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc);
167d99a0153SChris Williamson fs->jpc = NO_JUMP;
168d99a0153SChris Williamson }
169d99a0153SChris Williamson
170d99a0153SChris Williamson
luaK_patchlist(FuncState * fs,int list,int target)171d99a0153SChris Williamson void luaK_patchlist (FuncState *fs, int list, int target) {
172d99a0153SChris Williamson if (target == fs->pc)
173d99a0153SChris Williamson luaK_patchtohere(fs, list);
174d99a0153SChris Williamson else {
175d99a0153SChris Williamson lua_assert(target < fs->pc);
176d99a0153SChris Williamson patchlistaux(fs, list, target, NO_REG, target);
177d99a0153SChris Williamson }
178d99a0153SChris Williamson }
179d99a0153SChris Williamson
180d99a0153SChris Williamson
luaK_patchclose(FuncState * fs,int list,int level)181d99a0153SChris Williamson LUAI_FUNC void luaK_patchclose (FuncState *fs, int list, int level) {
182d99a0153SChris Williamson level++; /* argument is +1 to reserve 0 as non-op */
183d99a0153SChris Williamson while (list != NO_JUMP) {
184d99a0153SChris Williamson int next = getjump(fs, list);
185d99a0153SChris Williamson lua_assert(GET_OPCODE(fs->f->code[list]) == OP_JMP &&
186d99a0153SChris Williamson (GETARG_A(fs->f->code[list]) == 0 ||
187d99a0153SChris Williamson GETARG_A(fs->f->code[list]) >= level));
188d99a0153SChris Williamson SETARG_A(fs->f->code[list], level);
189d99a0153SChris Williamson list = next;
190d99a0153SChris Williamson }
191d99a0153SChris Williamson }
192d99a0153SChris Williamson
193d99a0153SChris Williamson
luaK_patchtohere(FuncState * fs,int list)194d99a0153SChris Williamson void luaK_patchtohere (FuncState *fs, int list) {
195d99a0153SChris Williamson luaK_getlabel(fs);
196d99a0153SChris Williamson luaK_concat(fs, &fs->jpc, list);
197d99a0153SChris Williamson }
198d99a0153SChris Williamson
199d99a0153SChris Williamson
luaK_concat(FuncState * fs,int * l1,int l2)200d99a0153SChris Williamson void luaK_concat (FuncState *fs, int *l1, int l2) {
201d99a0153SChris Williamson if (l2 == NO_JUMP) return;
202d99a0153SChris Williamson else if (*l1 == NO_JUMP)
203d99a0153SChris Williamson *l1 = l2;
204d99a0153SChris Williamson else {
205d99a0153SChris Williamson int list = *l1;
206d99a0153SChris Williamson int next;
207d99a0153SChris Williamson while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */
208d99a0153SChris Williamson list = next;
209d99a0153SChris Williamson fixjump(fs, list, l2);
210d99a0153SChris Williamson }
211d99a0153SChris Williamson }
212d99a0153SChris Williamson
213d99a0153SChris Williamson
luaK_code(FuncState * fs,Instruction i)214d99a0153SChris Williamson static int luaK_code (FuncState *fs, Instruction i) {
215d99a0153SChris Williamson Proto *f = fs->f;
216d99a0153SChris Williamson dischargejpc(fs); /* `pc' will change */
217d99a0153SChris Williamson /* put new instruction in code array */
218d99a0153SChris Williamson luaM_growvector(fs->ls->L, f->code, fs->pc, f->sizecode, Instruction,
219d99a0153SChris Williamson MAX_INT, "opcodes");
220d99a0153SChris Williamson f->code[fs->pc] = i;
221d99a0153SChris Williamson /* save corresponding line information */
222d99a0153SChris Williamson luaM_growvector(fs->ls->L, f->lineinfo, fs->pc, f->sizelineinfo, int,
223d99a0153SChris Williamson MAX_INT, "opcodes");
224d99a0153SChris Williamson f->lineinfo[fs->pc] = fs->ls->lastline;
225d99a0153SChris Williamson return fs->pc++;
226d99a0153SChris Williamson }
227d99a0153SChris Williamson
228d99a0153SChris Williamson
luaK_codeABC(FuncState * fs,OpCode o,int a,int b,int c)229d99a0153SChris Williamson int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) {
230d99a0153SChris Williamson lua_assert(getOpMode(o) == iABC);
231d99a0153SChris Williamson lua_assert(getBMode(o) != OpArgN || b == 0);
232d99a0153SChris Williamson lua_assert(getCMode(o) != OpArgN || c == 0);
233d99a0153SChris Williamson lua_assert(a <= MAXARG_A && b <= MAXARG_B && c <= MAXARG_C);
234d99a0153SChris Williamson return luaK_code(fs, CREATE_ABC(o, a, b, c));
235d99a0153SChris Williamson }
236d99a0153SChris Williamson
237d99a0153SChris Williamson
luaK_codeABx(FuncState * fs,OpCode o,int a,unsigned int bc)238d99a0153SChris Williamson int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) {
239d99a0153SChris Williamson lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx);
240d99a0153SChris Williamson lua_assert(getCMode(o) == OpArgN);
241d99a0153SChris Williamson lua_assert(a <= MAXARG_A && bc <= MAXARG_Bx);
242d99a0153SChris Williamson return luaK_code(fs, CREATE_ABx(o, a, bc));
243d99a0153SChris Williamson }
244d99a0153SChris Williamson
245d99a0153SChris Williamson
codeextraarg(FuncState * fs,int a)246d99a0153SChris Williamson static int codeextraarg (FuncState *fs, int a) {
247d99a0153SChris Williamson lua_assert(a <= MAXARG_Ax);
248d99a0153SChris Williamson return luaK_code(fs, CREATE_Ax(OP_EXTRAARG, a));
249d99a0153SChris Williamson }
250d99a0153SChris Williamson
251d99a0153SChris Williamson
luaK_codek(FuncState * fs,int reg,int k)252d99a0153SChris Williamson int luaK_codek (FuncState *fs, int reg, int k) {
253d99a0153SChris Williamson if (k <= MAXARG_Bx)
254d99a0153SChris Williamson return luaK_codeABx(fs, OP_LOADK, reg, k);
255d99a0153SChris Williamson else {
256d99a0153SChris Williamson int p = luaK_codeABx(fs, OP_LOADKX, reg, 0);
257d99a0153SChris Williamson codeextraarg(fs, k);
258d99a0153SChris Williamson return p;
259d99a0153SChris Williamson }
260d99a0153SChris Williamson }
261d99a0153SChris Williamson
262d99a0153SChris Williamson
luaK_checkstack(FuncState * fs,int n)263d99a0153SChris Williamson void luaK_checkstack (FuncState *fs, int n) {
264d99a0153SChris Williamson int newstack = fs->freereg + n;
265d99a0153SChris Williamson if (newstack > fs->f->maxstacksize) {
266d99a0153SChris Williamson if (newstack >= MAXSTACK)
267d99a0153SChris Williamson luaX_syntaxerror(fs->ls, "function or expression too complex");
268d99a0153SChris Williamson fs->f->maxstacksize = cast_byte(newstack);
269d99a0153SChris Williamson }
270d99a0153SChris Williamson }
271d99a0153SChris Williamson
272d99a0153SChris Williamson
luaK_reserveregs(FuncState * fs,int n)273d99a0153SChris Williamson void luaK_reserveregs (FuncState *fs, int n) {
274d99a0153SChris Williamson luaK_checkstack(fs, n);
275d99a0153SChris Williamson fs->freereg += n;
276d99a0153SChris Williamson }
277d99a0153SChris Williamson
278d99a0153SChris Williamson
freereg(FuncState * fs,int reg)279d99a0153SChris Williamson static void freereg (FuncState *fs, int reg) {
280d99a0153SChris Williamson if (!ISK(reg) && reg >= fs->nactvar) {
281d99a0153SChris Williamson fs->freereg--;
282d99a0153SChris Williamson lua_assert(reg == fs->freereg);
283d99a0153SChris Williamson }
284d99a0153SChris Williamson }
285d99a0153SChris Williamson
286d99a0153SChris Williamson
freeexp(FuncState * fs,expdesc * e)287d99a0153SChris Williamson static void freeexp (FuncState *fs, expdesc *e) {
288d99a0153SChris Williamson if (e->k == VNONRELOC)
289d99a0153SChris Williamson freereg(fs, e->u.info);
290d99a0153SChris Williamson }
291d99a0153SChris Williamson
292d99a0153SChris Williamson
addk(FuncState * fs,TValue * key,TValue * v)293d99a0153SChris Williamson static int addk (FuncState *fs, TValue *key, TValue *v) {
294d99a0153SChris Williamson lua_State *L = fs->ls->L;
295d99a0153SChris Williamson TValue *idx = luaH_set(L, fs->h, key);
296d99a0153SChris Williamson Proto *f = fs->f;
297d99a0153SChris Williamson int k, oldsize;
298d99a0153SChris Williamson if (ttisnumber(idx)) {
299d99a0153SChris Williamson lua_Number n = nvalue(idx);
300d99a0153SChris Williamson lua_number2int(k, n);
301d99a0153SChris Williamson if (luaV_rawequalobj(&f->k[k], v))
302d99a0153SChris Williamson return k;
303d99a0153SChris Williamson /* else may be a collision (e.g., between 0.0 and "\0\0\0\0\0\0\0\0");
304d99a0153SChris Williamson go through and create a new entry for this value */
305d99a0153SChris Williamson }
306d99a0153SChris Williamson /* constant not found; create a new entry */
307d99a0153SChris Williamson oldsize = f->sizek;
308d99a0153SChris Williamson k = fs->nk;
309d99a0153SChris Williamson /* numerical value does not need GC barrier;
310d99a0153SChris Williamson table has no metatable, so it does not need to invalidate cache */
311d99a0153SChris Williamson setnvalue(idx, cast_num(k));
312d99a0153SChris Williamson luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants");
313d99a0153SChris Williamson while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]);
314d99a0153SChris Williamson setobj(L, &f->k[k], v);
315d99a0153SChris Williamson fs->nk++;
316d99a0153SChris Williamson luaC_barrier(L, f, v);
317d99a0153SChris Williamson return k;
318d99a0153SChris Williamson }
319d99a0153SChris Williamson
320d99a0153SChris Williamson
luaK_stringK(FuncState * fs,TString * s)321d99a0153SChris Williamson int luaK_stringK (FuncState *fs, TString *s) {
322d99a0153SChris Williamson TValue o;
323d99a0153SChris Williamson setsvalue(fs->ls->L, &o, s);
324d99a0153SChris Williamson return addk(fs, &o, &o);
325d99a0153SChris Williamson }
326d99a0153SChris Williamson
327d99a0153SChris Williamson
luaK_numberK(FuncState * fs,lua_Number r)328d99a0153SChris Williamson int luaK_numberK (FuncState *fs, lua_Number r) {
329d99a0153SChris Williamson int n;
330d99a0153SChris Williamson lua_State *L = fs->ls->L;
331d99a0153SChris Williamson TValue o;
332d99a0153SChris Williamson setnvalue(&o, r);
333d99a0153SChris Williamson if (r == 0 || luai_numisnan(NULL, r)) { /* handle -0 and NaN */
334d99a0153SChris Williamson /* use raw representation as key to avoid numeric problems */
335d99a0153SChris Williamson setsvalue(L, L->top++, luaS_newlstr(L, (char *)&r, sizeof(r)));
336d99a0153SChris Williamson n = addk(fs, L->top - 1, &o);
337d99a0153SChris Williamson L->top--;
338d99a0153SChris Williamson }
339d99a0153SChris Williamson else
340d99a0153SChris Williamson n = addk(fs, &o, &o); /* regular case */
341d99a0153SChris Williamson return n;
342d99a0153SChris Williamson }
343d99a0153SChris Williamson
344d99a0153SChris Williamson
boolK(FuncState * fs,int b)345d99a0153SChris Williamson static int boolK (FuncState *fs, int b) {
346d99a0153SChris Williamson TValue o;
347d99a0153SChris Williamson setbvalue(&o, b);
348d99a0153SChris Williamson return addk(fs, &o, &o);
349d99a0153SChris Williamson }
350d99a0153SChris Williamson
351d99a0153SChris Williamson
nilK(FuncState * fs)352d99a0153SChris Williamson static int nilK (FuncState *fs) {
353d99a0153SChris Williamson TValue k, v;
354d99a0153SChris Williamson setnilvalue(&v);
355d99a0153SChris Williamson /* cannot use nil as key; instead use table itself to represent nil */
356d99a0153SChris Williamson sethvalue(fs->ls->L, &k, fs->h);
357d99a0153SChris Williamson return addk(fs, &k, &v);
358d99a0153SChris Williamson }
359d99a0153SChris Williamson
360d99a0153SChris Williamson
luaK_setreturns(FuncState * fs,expdesc * e,int nresults)361d99a0153SChris Williamson void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) {
362d99a0153SChris Williamson if (e->k == VCALL) { /* expression is an open function call? */
363d99a0153SChris Williamson SETARG_C(getcode(fs, e), nresults+1);
364d99a0153SChris Williamson }
365d99a0153SChris Williamson else if (e->k == VVARARG) {
366d99a0153SChris Williamson SETARG_B(getcode(fs, e), nresults+1);
367d99a0153SChris Williamson SETARG_A(getcode(fs, e), fs->freereg);
368d99a0153SChris Williamson luaK_reserveregs(fs, 1);
369d99a0153SChris Williamson }
370d99a0153SChris Williamson }
371d99a0153SChris Williamson
372d99a0153SChris Williamson
luaK_setoneret(FuncState * fs,expdesc * e)373d99a0153SChris Williamson void luaK_setoneret (FuncState *fs, expdesc *e) {
374d99a0153SChris Williamson if (e->k == VCALL) { /* expression is an open function call? */
375d99a0153SChris Williamson e->k = VNONRELOC;
376d99a0153SChris Williamson e->u.info = GETARG_A(getcode(fs, e));
377d99a0153SChris Williamson }
378d99a0153SChris Williamson else if (e->k == VVARARG) {
379d99a0153SChris Williamson SETARG_B(getcode(fs, e), 2);
380d99a0153SChris Williamson e->k = VRELOCABLE; /* can relocate its simple result */
381d99a0153SChris Williamson }
382d99a0153SChris Williamson }
383d99a0153SChris Williamson
384d99a0153SChris Williamson
luaK_dischargevars(FuncState * fs,expdesc * e)385d99a0153SChris Williamson void luaK_dischargevars (FuncState *fs, expdesc *e) {
386d99a0153SChris Williamson switch (e->k) {
387d99a0153SChris Williamson case VLOCAL: {
388d99a0153SChris Williamson e->k = VNONRELOC;
389d99a0153SChris Williamson break;
390d99a0153SChris Williamson }
391d99a0153SChris Williamson case VUPVAL: {
392d99a0153SChris Williamson e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0);
393d99a0153SChris Williamson e->k = VRELOCABLE;
394d99a0153SChris Williamson break;
395d99a0153SChris Williamson }
396d99a0153SChris Williamson case VINDEXED: {
397d99a0153SChris Williamson OpCode op = OP_GETTABUP; /* assume 't' is in an upvalue */
398d99a0153SChris Williamson freereg(fs, e->u.ind.idx);
399d99a0153SChris Williamson if (e->u.ind.vt == VLOCAL) { /* 't' is in a register? */
400d99a0153SChris Williamson freereg(fs, e->u.ind.t);
401d99a0153SChris Williamson op = OP_GETTABLE;
402d99a0153SChris Williamson }
403d99a0153SChris Williamson e->u.info = luaK_codeABC(fs, op, 0, e->u.ind.t, e->u.ind.idx);
404d99a0153SChris Williamson e->k = VRELOCABLE;
405d99a0153SChris Williamson break;
406d99a0153SChris Williamson }
407d99a0153SChris Williamson case VVARARG:
408d99a0153SChris Williamson case VCALL: {
409d99a0153SChris Williamson luaK_setoneret(fs, e);
410d99a0153SChris Williamson break;
411d99a0153SChris Williamson }
412d99a0153SChris Williamson default: break; /* there is one value available (somewhere) */
413d99a0153SChris Williamson }
414d99a0153SChris Williamson }
415d99a0153SChris Williamson
416d99a0153SChris Williamson
code_label(FuncState * fs,int A,int b,int jump)417d99a0153SChris Williamson static int code_label (FuncState *fs, int A, int b, int jump) {
418d99a0153SChris Williamson luaK_getlabel(fs); /* those instructions may be jump targets */
419d99a0153SChris Williamson return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump);
420d99a0153SChris Williamson }
421d99a0153SChris Williamson
422d99a0153SChris Williamson
discharge2reg(FuncState * fs,expdesc * e,int reg)423d99a0153SChris Williamson static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
424d99a0153SChris Williamson luaK_dischargevars(fs, e);
425d99a0153SChris Williamson switch (e->k) {
426d99a0153SChris Williamson case VNIL: {
427d99a0153SChris Williamson luaK_nil(fs, reg, 1);
428d99a0153SChris Williamson break;
429d99a0153SChris Williamson }
430d99a0153SChris Williamson case VFALSE: case VTRUE: {
431d99a0153SChris Williamson luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0);
432d99a0153SChris Williamson break;
433d99a0153SChris Williamson }
434d99a0153SChris Williamson case VK: {
435d99a0153SChris Williamson luaK_codek(fs, reg, e->u.info);
436d99a0153SChris Williamson break;
437d99a0153SChris Williamson }
438d99a0153SChris Williamson case VKNUM: {
439d99a0153SChris Williamson luaK_codek(fs, reg, luaK_numberK(fs, e->u.nval));
440d99a0153SChris Williamson break;
441d99a0153SChris Williamson }
442d99a0153SChris Williamson case VRELOCABLE: {
443d99a0153SChris Williamson Instruction *pc = &getcode(fs, e);
444d99a0153SChris Williamson SETARG_A(*pc, reg);
445d99a0153SChris Williamson break;
446d99a0153SChris Williamson }
447d99a0153SChris Williamson case VNONRELOC: {
448d99a0153SChris Williamson if (reg != e->u.info)
449d99a0153SChris Williamson luaK_codeABC(fs, OP_MOVE, reg, e->u.info, 0);
450d99a0153SChris Williamson break;
451d99a0153SChris Williamson }
452d99a0153SChris Williamson default: {
453d99a0153SChris Williamson lua_assert(e->k == VVOID || e->k == VJMP);
454d99a0153SChris Williamson return; /* nothing to do... */
455d99a0153SChris Williamson }
456d99a0153SChris Williamson }
457d99a0153SChris Williamson e->u.info = reg;
458d99a0153SChris Williamson e->k = VNONRELOC;
459d99a0153SChris Williamson }
460d99a0153SChris Williamson
461d99a0153SChris Williamson
discharge2anyreg(FuncState * fs,expdesc * e)462d99a0153SChris Williamson static void discharge2anyreg (FuncState *fs, expdesc *e) {
463d99a0153SChris Williamson if (e->k != VNONRELOC) {
464d99a0153SChris Williamson luaK_reserveregs(fs, 1);
465d99a0153SChris Williamson discharge2reg(fs, e, fs->freereg-1);
466d99a0153SChris Williamson }
467d99a0153SChris Williamson }
468d99a0153SChris Williamson
469d99a0153SChris Williamson
exp2reg(FuncState * fs,expdesc * e,int reg)470d99a0153SChris Williamson static void exp2reg (FuncState *fs, expdesc *e, int reg) {
471d99a0153SChris Williamson discharge2reg(fs, e, reg);
472d99a0153SChris Williamson if (e->k == VJMP)
473d99a0153SChris Williamson luaK_concat(fs, &e->t, e->u.info); /* put this jump in `t' list */
474d99a0153SChris Williamson if (hasjumps(e)) {
475d99a0153SChris Williamson int final; /* position after whole expression */
476d99a0153SChris Williamson int p_f = NO_JUMP; /* position of an eventual LOAD false */
477d99a0153SChris Williamson int p_t = NO_JUMP; /* position of an eventual LOAD true */
478d99a0153SChris Williamson if (need_value(fs, e->t) || need_value(fs, e->f)) {
479d99a0153SChris Williamson int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs);
480d99a0153SChris Williamson p_f = code_label(fs, reg, 0, 1);
481d99a0153SChris Williamson p_t = code_label(fs, reg, 1, 0);
482d99a0153SChris Williamson luaK_patchtohere(fs, fj);
483d99a0153SChris Williamson }
484d99a0153SChris Williamson final = luaK_getlabel(fs);
485d99a0153SChris Williamson patchlistaux(fs, e->f, final, reg, p_f);
486d99a0153SChris Williamson patchlistaux(fs, e->t, final, reg, p_t);
487d99a0153SChris Williamson }
488d99a0153SChris Williamson e->f = e->t = NO_JUMP;
489d99a0153SChris Williamson e->u.info = reg;
490d99a0153SChris Williamson e->k = VNONRELOC;
491d99a0153SChris Williamson }
492d99a0153SChris Williamson
493d99a0153SChris Williamson
luaK_exp2nextreg(FuncState * fs,expdesc * e)494d99a0153SChris Williamson void luaK_exp2nextreg (FuncState *fs, expdesc *e) {
495d99a0153SChris Williamson luaK_dischargevars(fs, e);
496d99a0153SChris Williamson freeexp(fs, e);
497d99a0153SChris Williamson luaK_reserveregs(fs, 1);
498d99a0153SChris Williamson exp2reg(fs, e, fs->freereg - 1);
499d99a0153SChris Williamson }
500d99a0153SChris Williamson
501d99a0153SChris Williamson
luaK_exp2anyreg(FuncState * fs,expdesc * e)502d99a0153SChris Williamson int luaK_exp2anyreg (FuncState *fs, expdesc *e) {
503d99a0153SChris Williamson luaK_dischargevars(fs, e);
504d99a0153SChris Williamson if (e->k == VNONRELOC) {
505d99a0153SChris Williamson if (!hasjumps(e)) return e->u.info; /* exp is already in a register */
506d99a0153SChris Williamson if (e->u.info >= fs->nactvar) { /* reg. is not a local? */
507d99a0153SChris Williamson exp2reg(fs, e, e->u.info); /* put value on it */
508d99a0153SChris Williamson return e->u.info;
509d99a0153SChris Williamson }
510d99a0153SChris Williamson }
511d99a0153SChris Williamson luaK_exp2nextreg(fs, e); /* default */
512d99a0153SChris Williamson return e->u.info;
513d99a0153SChris Williamson }
514d99a0153SChris Williamson
515d99a0153SChris Williamson
luaK_exp2anyregup(FuncState * fs,expdesc * e)516d99a0153SChris Williamson void luaK_exp2anyregup (FuncState *fs, expdesc *e) {
517d99a0153SChris Williamson if (e->k != VUPVAL || hasjumps(e))
518d99a0153SChris Williamson luaK_exp2anyreg(fs, e);
519d99a0153SChris Williamson }
520d99a0153SChris Williamson
521d99a0153SChris Williamson
luaK_exp2val(FuncState * fs,expdesc * e)522d99a0153SChris Williamson void luaK_exp2val (FuncState *fs, expdesc *e) {
523d99a0153SChris Williamson if (hasjumps(e))
524d99a0153SChris Williamson luaK_exp2anyreg(fs, e);
525d99a0153SChris Williamson else
526d99a0153SChris Williamson luaK_dischargevars(fs, e);
527d99a0153SChris Williamson }
528d99a0153SChris Williamson
529d99a0153SChris Williamson
luaK_exp2RK(FuncState * fs,expdesc * e)530d99a0153SChris Williamson int luaK_exp2RK (FuncState *fs, expdesc *e) {
531d99a0153SChris Williamson luaK_exp2val(fs, e);
532d99a0153SChris Williamson switch (e->k) {
533d99a0153SChris Williamson case VTRUE:
534d99a0153SChris Williamson case VFALSE:
535d99a0153SChris Williamson case VNIL: {
536d99a0153SChris Williamson if (fs->nk <= MAXINDEXRK) { /* constant fits in RK operand? */
537d99a0153SChris Williamson e->u.info = (e->k == VNIL) ? nilK(fs) : boolK(fs, (e->k == VTRUE));
538d99a0153SChris Williamson e->k = VK;
539d99a0153SChris Williamson return RKASK(e->u.info);
540d99a0153SChris Williamson }
541d99a0153SChris Williamson else break;
542d99a0153SChris Williamson }
543d99a0153SChris Williamson case VKNUM: {
544d99a0153SChris Williamson e->u.info = luaK_numberK(fs, e->u.nval);
545d99a0153SChris Williamson e->k = VK;
546d99a0153SChris Williamson /* go through */
547d99a0153SChris Williamson }
548d99a0153SChris Williamson case VK: {
549d99a0153SChris Williamson if (e->u.info <= MAXINDEXRK) /* constant fits in argC? */
550d99a0153SChris Williamson return RKASK(e->u.info);
551d99a0153SChris Williamson else break;
552d99a0153SChris Williamson }
553d99a0153SChris Williamson default: break;
554d99a0153SChris Williamson }
555d99a0153SChris Williamson /* not a constant in the right range: put it in a register */
556d99a0153SChris Williamson return luaK_exp2anyreg(fs, e);
557d99a0153SChris Williamson }
558d99a0153SChris Williamson
559d99a0153SChris Williamson
luaK_storevar(FuncState * fs,expdesc * var,expdesc * ex)560d99a0153SChris Williamson void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
561d99a0153SChris Williamson switch (var->k) {
562d99a0153SChris Williamson case VLOCAL: {
563d99a0153SChris Williamson freeexp(fs, ex);
564d99a0153SChris Williamson exp2reg(fs, ex, var->u.info);
565d99a0153SChris Williamson return;
566d99a0153SChris Williamson }
567d99a0153SChris Williamson case VUPVAL: {
568d99a0153SChris Williamson int e = luaK_exp2anyreg(fs, ex);
569d99a0153SChris Williamson luaK_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0);
570d99a0153SChris Williamson break;
571d99a0153SChris Williamson }
572d99a0153SChris Williamson case VINDEXED: {
573d99a0153SChris Williamson OpCode op = (var->u.ind.vt == VLOCAL) ? OP_SETTABLE : OP_SETTABUP;
574d99a0153SChris Williamson int e = luaK_exp2RK(fs, ex);
575d99a0153SChris Williamson luaK_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e);
576d99a0153SChris Williamson break;
577d99a0153SChris Williamson }
578d99a0153SChris Williamson default: {
579d99a0153SChris Williamson lua_assert(0); /* invalid var kind to store */
580d99a0153SChris Williamson break;
581d99a0153SChris Williamson }
582d99a0153SChris Williamson }
583d99a0153SChris Williamson freeexp(fs, ex);
584d99a0153SChris Williamson }
585d99a0153SChris Williamson
586d99a0153SChris Williamson
luaK_self(FuncState * fs,expdesc * e,expdesc * key)587d99a0153SChris Williamson void luaK_self (FuncState *fs, expdesc *e, expdesc *key) {
588d99a0153SChris Williamson int ereg;
589d99a0153SChris Williamson luaK_exp2anyreg(fs, e);
590d99a0153SChris Williamson ereg = e->u.info; /* register where 'e' was placed */
591d99a0153SChris Williamson freeexp(fs, e);
592d99a0153SChris Williamson e->u.info = fs->freereg; /* base register for op_self */
593d99a0153SChris Williamson e->k = VNONRELOC;
594d99a0153SChris Williamson luaK_reserveregs(fs, 2); /* function and 'self' produced by op_self */
595d99a0153SChris Williamson luaK_codeABC(fs, OP_SELF, e->u.info, ereg, luaK_exp2RK(fs, key));
596d99a0153SChris Williamson freeexp(fs, key);
597d99a0153SChris Williamson }
598d99a0153SChris Williamson
599d99a0153SChris Williamson
invertjump(FuncState * fs,expdesc * e)600d99a0153SChris Williamson static void invertjump (FuncState *fs, expdesc *e) {
601d99a0153SChris Williamson Instruction *pc = getjumpcontrol(fs, e->u.info);
602d99a0153SChris Williamson lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET &&
603d99a0153SChris Williamson GET_OPCODE(*pc) != OP_TEST);
604d99a0153SChris Williamson SETARG_A(*pc, !(GETARG_A(*pc)));
605d99a0153SChris Williamson }
606d99a0153SChris Williamson
607d99a0153SChris Williamson
jumponcond(FuncState * fs,expdesc * e,int cond)608d99a0153SChris Williamson static int jumponcond (FuncState *fs, expdesc *e, int cond) {
609d99a0153SChris Williamson if (e->k == VRELOCABLE) {
610d99a0153SChris Williamson Instruction ie = getcode(fs, e);
611d99a0153SChris Williamson if (GET_OPCODE(ie) == OP_NOT) {
612d99a0153SChris Williamson fs->pc--; /* remove previous OP_NOT */
613d99a0153SChris Williamson return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond);
614d99a0153SChris Williamson }
615d99a0153SChris Williamson /* else go through */
616d99a0153SChris Williamson }
617d99a0153SChris Williamson discharge2anyreg(fs, e);
618d99a0153SChris Williamson freeexp(fs, e);
619d99a0153SChris Williamson return condjump(fs, OP_TESTSET, NO_REG, e->u.info, cond);
620d99a0153SChris Williamson }
621d99a0153SChris Williamson
622d99a0153SChris Williamson
luaK_goiftrue(FuncState * fs,expdesc * e)623d99a0153SChris Williamson void luaK_goiftrue (FuncState *fs, expdesc *e) {
624d99a0153SChris Williamson int pc; /* pc of last jump */
625d99a0153SChris Williamson luaK_dischargevars(fs, e);
626d99a0153SChris Williamson switch (e->k) {
627d99a0153SChris Williamson case VJMP: {
628d99a0153SChris Williamson invertjump(fs, e);
629d99a0153SChris Williamson pc = e->u.info;
630d99a0153SChris Williamson break;
631d99a0153SChris Williamson }
632d99a0153SChris Williamson case VK: case VKNUM: case VTRUE: {
633d99a0153SChris Williamson pc = NO_JUMP; /* always true; do nothing */
634d99a0153SChris Williamson break;
635d99a0153SChris Williamson }
636d99a0153SChris Williamson default: {
637d99a0153SChris Williamson pc = jumponcond(fs, e, 0);
638d99a0153SChris Williamson break;
639d99a0153SChris Williamson }
640d99a0153SChris Williamson }
641d99a0153SChris Williamson luaK_concat(fs, &e->f, pc); /* insert last jump in `f' list */
642d99a0153SChris Williamson luaK_patchtohere(fs, e->t);
643d99a0153SChris Williamson e->t = NO_JUMP;
644d99a0153SChris Williamson }
645d99a0153SChris Williamson
646d99a0153SChris Williamson
luaK_goiffalse(FuncState * fs,expdesc * e)647d99a0153SChris Williamson void luaK_goiffalse (FuncState *fs, expdesc *e) {
648d99a0153SChris Williamson int pc; /* pc of last jump */
649d99a0153SChris Williamson luaK_dischargevars(fs, e);
650d99a0153SChris Williamson switch (e->k) {
651d99a0153SChris Williamson case VJMP: {
652d99a0153SChris Williamson pc = e->u.info;
653d99a0153SChris Williamson break;
654d99a0153SChris Williamson }
655d99a0153SChris Williamson case VNIL: case VFALSE: {
656d99a0153SChris Williamson pc = NO_JUMP; /* always false; do nothing */
657d99a0153SChris Williamson break;
658d99a0153SChris Williamson }
659d99a0153SChris Williamson default: {
660d99a0153SChris Williamson pc = jumponcond(fs, e, 1);
661d99a0153SChris Williamson break;
662d99a0153SChris Williamson }
663d99a0153SChris Williamson }
664d99a0153SChris Williamson luaK_concat(fs, &e->t, pc); /* insert last jump in `t' list */
665d99a0153SChris Williamson luaK_patchtohere(fs, e->f);
666d99a0153SChris Williamson e->f = NO_JUMP;
667d99a0153SChris Williamson }
668d99a0153SChris Williamson
669d99a0153SChris Williamson
codenot(FuncState * fs,expdesc * e)670d99a0153SChris Williamson static void codenot (FuncState *fs, expdesc *e) {
671d99a0153SChris Williamson luaK_dischargevars(fs, e);
672d99a0153SChris Williamson switch (e->k) {
673d99a0153SChris Williamson case VNIL: case VFALSE: {
674d99a0153SChris Williamson e->k = VTRUE;
675d99a0153SChris Williamson break;
676d99a0153SChris Williamson }
677d99a0153SChris Williamson case VK: case VKNUM: case VTRUE: {
678d99a0153SChris Williamson e->k = VFALSE;
679d99a0153SChris Williamson break;
680d99a0153SChris Williamson }
681d99a0153SChris Williamson case VJMP: {
682d99a0153SChris Williamson invertjump(fs, e);
683d99a0153SChris Williamson break;
684d99a0153SChris Williamson }
685d99a0153SChris Williamson case VRELOCABLE:
686d99a0153SChris Williamson case VNONRELOC: {
687d99a0153SChris Williamson discharge2anyreg(fs, e);
688d99a0153SChris Williamson freeexp(fs, e);
689d99a0153SChris Williamson e->u.info = luaK_codeABC(fs, OP_NOT, 0, e->u.info, 0);
690d99a0153SChris Williamson e->k = VRELOCABLE;
691d99a0153SChris Williamson break;
692d99a0153SChris Williamson }
693d99a0153SChris Williamson default: {
694d99a0153SChris Williamson lua_assert(0); /* cannot happen */
695d99a0153SChris Williamson break;
696d99a0153SChris Williamson }
697d99a0153SChris Williamson }
698d99a0153SChris Williamson /* interchange true and false lists */
699d99a0153SChris Williamson { int temp = e->f; e->f = e->t; e->t = temp; }
700d99a0153SChris Williamson removevalues(fs, e->f);
701d99a0153SChris Williamson removevalues(fs, e->t);
702d99a0153SChris Williamson }
703d99a0153SChris Williamson
704d99a0153SChris Williamson
luaK_indexed(FuncState * fs,expdesc * t,expdesc * k)705d99a0153SChris Williamson void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
706d99a0153SChris Williamson lua_assert(!hasjumps(t));
707d99a0153SChris Williamson t->u.ind.t = t->u.info;
708d99a0153SChris Williamson t->u.ind.idx = luaK_exp2RK(fs, k);
709d99a0153SChris Williamson t->u.ind.vt = (t->k == VUPVAL) ? VUPVAL
710d99a0153SChris Williamson : check_exp(vkisinreg(t->k), VLOCAL);
711d99a0153SChris Williamson t->k = VINDEXED;
712d99a0153SChris Williamson }
713d99a0153SChris Williamson
714d99a0153SChris Williamson
constfolding(OpCode op,expdesc * e1,expdesc * e2)715d99a0153SChris Williamson static int constfolding (OpCode op, expdesc *e1, expdesc *e2) {
716d99a0153SChris Williamson lua_Number r;
717d99a0153SChris Williamson if (!isnumeral(e1) || !isnumeral(e2)) return 0;
718d99a0153SChris Williamson if ((op == OP_DIV || op == OP_MOD) && e2->u.nval == 0)
719d99a0153SChris Williamson return 0; /* do not attempt to divide by 0 */
720d99a0153SChris Williamson /*
721d99a0153SChris Williamson * Patched: check for MIN_INT / -1
722d99a0153SChris Williamson */
723d99a0153SChris Williamson if (op == OP_DIV && e1->u.nval == INT64_MIN && e2->u.nval == -1)
724d99a0153SChris Williamson return 0;
725d99a0153SChris Williamson r = luaO_arith(op - OP_ADD + LUA_OPADD, e1->u.nval, e2->u.nval);
726d99a0153SChris Williamson e1->u.nval = r;
727d99a0153SChris Williamson return 1;
728d99a0153SChris Williamson }
729d99a0153SChris Williamson
730d99a0153SChris Williamson
codearith(FuncState * fs,OpCode op,expdesc * e1,expdesc * e2,int line)731d99a0153SChris Williamson static void codearith (FuncState *fs, OpCode op,
732d99a0153SChris Williamson expdesc *e1, expdesc *e2, int line) {
733d99a0153SChris Williamson if (constfolding(op, e1, e2))
734d99a0153SChris Williamson return;
735d99a0153SChris Williamson else {
736d99a0153SChris Williamson int o2 = (op != OP_UNM && op != OP_LEN) ? luaK_exp2RK(fs, e2) : 0;
737d99a0153SChris Williamson int o1 = luaK_exp2RK(fs, e1);
738d99a0153SChris Williamson if (o1 > o2) {
739d99a0153SChris Williamson freeexp(fs, e1);
740d99a0153SChris Williamson freeexp(fs, e2);
741d99a0153SChris Williamson }
742d99a0153SChris Williamson else {
743d99a0153SChris Williamson freeexp(fs, e2);
744d99a0153SChris Williamson freeexp(fs, e1);
745d99a0153SChris Williamson }
746d99a0153SChris Williamson e1->u.info = luaK_codeABC(fs, op, 0, o1, o2);
747d99a0153SChris Williamson e1->k = VRELOCABLE;
748d99a0153SChris Williamson luaK_fixline(fs, line);
749d99a0153SChris Williamson }
750d99a0153SChris Williamson }
751d99a0153SChris Williamson
752d99a0153SChris Williamson
codecomp(FuncState * fs,OpCode op,int cond,expdesc * e1,expdesc * e2)753d99a0153SChris Williamson static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1,
754d99a0153SChris Williamson expdesc *e2) {
755d99a0153SChris Williamson int o1 = luaK_exp2RK(fs, e1);
756d99a0153SChris Williamson int o2 = luaK_exp2RK(fs, e2);
757d99a0153SChris Williamson freeexp(fs, e2);
758d99a0153SChris Williamson freeexp(fs, e1);
759d99a0153SChris Williamson if (cond == 0 && op != OP_EQ) {
760d99a0153SChris Williamson int temp; /* exchange args to replace by `<' or `<=' */
761d99a0153SChris Williamson temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */
762d99a0153SChris Williamson cond = 1;
763d99a0153SChris Williamson }
764d99a0153SChris Williamson e1->u.info = condjump(fs, op, cond, o1, o2);
765d99a0153SChris Williamson e1->k = VJMP;
766d99a0153SChris Williamson }
767d99a0153SChris Williamson
768d99a0153SChris Williamson
luaK_prefix(FuncState * fs,UnOpr op,expdesc * e,int line)769d99a0153SChris Williamson void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) {
770d99a0153SChris Williamson expdesc e2;
771d99a0153SChris Williamson e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0;
772d99a0153SChris Williamson switch (op) {
773d99a0153SChris Williamson case OPR_MINUS: {
774d99a0153SChris Williamson if (isnumeral(e)) /* minus constant? */
775d99a0153SChris Williamson e->u.nval = luai_numunm(NULL, e->u.nval); /* fold it */
776d99a0153SChris Williamson else {
777d99a0153SChris Williamson luaK_exp2anyreg(fs, e);
778d99a0153SChris Williamson codearith(fs, OP_UNM, e, &e2, line);
779d99a0153SChris Williamson }
780d99a0153SChris Williamson break;
781d99a0153SChris Williamson }
782d99a0153SChris Williamson case OPR_NOT: codenot(fs, e); break;
783d99a0153SChris Williamson case OPR_LEN: {
784d99a0153SChris Williamson luaK_exp2anyreg(fs, e); /* cannot operate on constants */
785d99a0153SChris Williamson codearith(fs, OP_LEN, e, &e2, line);
786d99a0153SChris Williamson break;
787d99a0153SChris Williamson }
788d99a0153SChris Williamson default: lua_assert(0);
789d99a0153SChris Williamson }
790d99a0153SChris Williamson }
791d99a0153SChris Williamson
792d99a0153SChris Williamson
luaK_infix(FuncState * fs,BinOpr op,expdesc * v)793d99a0153SChris Williamson void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
794d99a0153SChris Williamson switch (op) {
795d99a0153SChris Williamson case OPR_AND: {
796d99a0153SChris Williamson luaK_goiftrue(fs, v);
797d99a0153SChris Williamson break;
798d99a0153SChris Williamson }
799d99a0153SChris Williamson case OPR_OR: {
800d99a0153SChris Williamson luaK_goiffalse(fs, v);
801d99a0153SChris Williamson break;
802d99a0153SChris Williamson }
803d99a0153SChris Williamson case OPR_CONCAT: {
804d99a0153SChris Williamson luaK_exp2nextreg(fs, v); /* operand must be on the `stack' */
805d99a0153SChris Williamson break;
806d99a0153SChris Williamson }
807d99a0153SChris Williamson case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV:
808d99a0153SChris Williamson case OPR_MOD: case OPR_POW: {
809d99a0153SChris Williamson if (!isnumeral(v)) luaK_exp2RK(fs, v);
810d99a0153SChris Williamson break;
811d99a0153SChris Williamson }
812d99a0153SChris Williamson default: {
813d99a0153SChris Williamson luaK_exp2RK(fs, v);
814d99a0153SChris Williamson break;
815d99a0153SChris Williamson }
816d99a0153SChris Williamson }
817d99a0153SChris Williamson }
818d99a0153SChris Williamson
819d99a0153SChris Williamson
luaK_posfix(FuncState * fs,BinOpr op,expdesc * e1,expdesc * e2,int line)820d99a0153SChris Williamson void luaK_posfix (FuncState *fs, BinOpr op,
821d99a0153SChris Williamson expdesc *e1, expdesc *e2, int line) {
822d99a0153SChris Williamson switch (op) {
823d99a0153SChris Williamson case OPR_AND: {
824d99a0153SChris Williamson lua_assert(e1->t == NO_JUMP); /* list must be closed */
825d99a0153SChris Williamson luaK_dischargevars(fs, e2);
826d99a0153SChris Williamson luaK_concat(fs, &e2->f, e1->f);
827d99a0153SChris Williamson *e1 = *e2;
828d99a0153SChris Williamson break;
829d99a0153SChris Williamson }
830d99a0153SChris Williamson case OPR_OR: {
831d99a0153SChris Williamson lua_assert(e1->f == NO_JUMP); /* list must be closed */
832d99a0153SChris Williamson luaK_dischargevars(fs, e2);
833d99a0153SChris Williamson luaK_concat(fs, &e2->t, e1->t);
834d99a0153SChris Williamson *e1 = *e2;
835d99a0153SChris Williamson break;
836d99a0153SChris Williamson }
837d99a0153SChris Williamson case OPR_CONCAT: {
838d99a0153SChris Williamson luaK_exp2val(fs, e2);
839d99a0153SChris Williamson if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) {
840d99a0153SChris Williamson lua_assert(e1->u.info == GETARG_B(getcode(fs, e2))-1);
841d99a0153SChris Williamson freeexp(fs, e1);
842d99a0153SChris Williamson SETARG_B(getcode(fs, e2), e1->u.info);
843d99a0153SChris Williamson e1->k = VRELOCABLE; e1->u.info = e2->u.info;
844d99a0153SChris Williamson }
845d99a0153SChris Williamson else {
846d99a0153SChris Williamson luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */
847d99a0153SChris Williamson codearith(fs, OP_CONCAT, e1, e2, line);
848d99a0153SChris Williamson }
849d99a0153SChris Williamson break;
850d99a0153SChris Williamson }
851d99a0153SChris Williamson case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV:
852d99a0153SChris Williamson case OPR_MOD: case OPR_POW: {
853d99a0153SChris Williamson codearith(fs, cast(OpCode, op - OPR_ADD + OP_ADD), e1, e2, line);
854d99a0153SChris Williamson break;
855d99a0153SChris Williamson }
856d99a0153SChris Williamson case OPR_EQ: case OPR_LT: case OPR_LE: {
857d99a0153SChris Williamson codecomp(fs, cast(OpCode, op - OPR_EQ + OP_EQ), 1, e1, e2);
858d99a0153SChris Williamson break;
859d99a0153SChris Williamson }
860d99a0153SChris Williamson case OPR_NE: case OPR_GT: case OPR_GE: {
861d99a0153SChris Williamson codecomp(fs, cast(OpCode, op - OPR_NE + OP_EQ), 0, e1, e2);
862d99a0153SChris Williamson break;
863d99a0153SChris Williamson }
864d99a0153SChris Williamson default: lua_assert(0);
865d99a0153SChris Williamson }
866d99a0153SChris Williamson }
867d99a0153SChris Williamson
868d99a0153SChris Williamson
luaK_fixline(FuncState * fs,int line)869d99a0153SChris Williamson void luaK_fixline (FuncState *fs, int line) {
870d99a0153SChris Williamson fs->f->lineinfo[fs->pc - 1] = line;
871d99a0153SChris Williamson }
872d99a0153SChris Williamson
873d99a0153SChris Williamson
luaK_setlist(FuncState * fs,int base,int nelems,int tostore)874d99a0153SChris Williamson void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) {
875d99a0153SChris Williamson int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1;
876d99a0153SChris Williamson int b = (tostore == LUA_MULTRET) ? 0 : tostore;
877d99a0153SChris Williamson lua_assert(tostore != 0);
878d99a0153SChris Williamson if (c <= MAXARG_C)
879d99a0153SChris Williamson luaK_codeABC(fs, OP_SETLIST, base, b, c);
880d99a0153SChris Williamson else if (c <= MAXARG_Ax) {
881d99a0153SChris Williamson luaK_codeABC(fs, OP_SETLIST, base, b, 0);
882d99a0153SChris Williamson codeextraarg(fs, c);
883d99a0153SChris Williamson }
884d99a0153SChris Williamson else
885d99a0153SChris Williamson luaX_syntaxerror(fs->ls, "constructor too long");
886d99a0153SChris Williamson fs->freereg = base + 1; /* free registers with list values */
887d99a0153SChris Williamson }
888