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