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