121d3294cSantirez /*
2*214adc50Santirez ** $Id: lcode.c,v 2.25.1.5 2011/01/31 14:53:16 roberto Exp $
321d3294cSantirez ** Code generator for Lua
421d3294cSantirez ** See Copyright Notice in lua.h
521d3294cSantirez */
621d3294cSantirez
721d3294cSantirez
821d3294cSantirez #include <stdlib.h>
921d3294cSantirez
1021d3294cSantirez #define lcode_c
1121d3294cSantirez #define LUA_CORE
1221d3294cSantirez
1321d3294cSantirez #include "lua.h"
1421d3294cSantirez
1521d3294cSantirez #include "lcode.h"
1621d3294cSantirez #include "ldebug.h"
1721d3294cSantirez #include "ldo.h"
1821d3294cSantirez #include "lgc.h"
1921d3294cSantirez #include "llex.h"
2021d3294cSantirez #include "lmem.h"
2121d3294cSantirez #include "lobject.h"
2221d3294cSantirez #include "lopcodes.h"
2321d3294cSantirez #include "lparser.h"
2421d3294cSantirez #include "ltable.h"
2521d3294cSantirez
2621d3294cSantirez
2721d3294cSantirez #define hasjumps(e) ((e)->t != (e)->f)
2821d3294cSantirez
2921d3294cSantirez
isnumeral(expdesc * e)3021d3294cSantirez static int isnumeral(expdesc *e) {
3121d3294cSantirez return (e->k == VKNUM && e->t == NO_JUMP && e->f == NO_JUMP);
3221d3294cSantirez }
3321d3294cSantirez
3421d3294cSantirez
luaK_nil(FuncState * fs,int from,int n)3521d3294cSantirez void luaK_nil (FuncState *fs, int from, int n) {
3621d3294cSantirez Instruction *previous;
3721d3294cSantirez if (fs->pc > fs->lasttarget) { /* no jumps to current position? */
3821d3294cSantirez if (fs->pc == 0) { /* function start? */
3921d3294cSantirez if (from >= fs->nactvar)
4021d3294cSantirez return; /* positions are already clean */
4121d3294cSantirez }
4221d3294cSantirez else {
4321d3294cSantirez previous = &fs->f->code[fs->pc-1];
4421d3294cSantirez if (GET_OPCODE(*previous) == OP_LOADNIL) {
4521d3294cSantirez int pfrom = GETARG_A(*previous);
4621d3294cSantirez int pto = GETARG_B(*previous);
4721d3294cSantirez if (pfrom <= from && from <= pto+1) { /* can connect both? */
4821d3294cSantirez if (from+n-1 > pto)
4921d3294cSantirez SETARG_B(*previous, from+n-1);
5021d3294cSantirez return;
5121d3294cSantirez }
5221d3294cSantirez }
5321d3294cSantirez }
5421d3294cSantirez }
5521d3294cSantirez luaK_codeABC(fs, OP_LOADNIL, from, from+n-1, 0); /* else no optimization */
5621d3294cSantirez }
5721d3294cSantirez
5821d3294cSantirez
luaK_jump(FuncState * fs)5921d3294cSantirez int luaK_jump (FuncState *fs) {
6021d3294cSantirez int jpc = fs->jpc; /* save list of jumps to here */
6121d3294cSantirez int j;
6221d3294cSantirez fs->jpc = NO_JUMP;
6321d3294cSantirez j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP);
6421d3294cSantirez luaK_concat(fs, &j, jpc); /* keep them on hold */
6521d3294cSantirez return j;
6621d3294cSantirez }
6721d3294cSantirez
6821d3294cSantirez
luaK_ret(FuncState * fs,int first,int nret)6921d3294cSantirez void luaK_ret (FuncState *fs, int first, int nret) {
7021d3294cSantirez luaK_codeABC(fs, OP_RETURN, first, nret+1, 0);
7121d3294cSantirez }
7221d3294cSantirez
7321d3294cSantirez
condjump(FuncState * fs,OpCode op,int A,int B,int C)7421d3294cSantirez static int condjump (FuncState *fs, OpCode op, int A, int B, int C) {
7521d3294cSantirez luaK_codeABC(fs, op, A, B, C);
7621d3294cSantirez return luaK_jump(fs);
7721d3294cSantirez }
7821d3294cSantirez
7921d3294cSantirez
fixjump(FuncState * fs,int pc,int dest)8021d3294cSantirez static void fixjump (FuncState *fs, int pc, int dest) {
8121d3294cSantirez Instruction *jmp = &fs->f->code[pc];
8221d3294cSantirez int offset = dest-(pc+1);
8321d3294cSantirez lua_assert(dest != NO_JUMP);
8421d3294cSantirez if (abs(offset) > MAXARG_sBx)
8521d3294cSantirez luaX_syntaxerror(fs->ls, "control structure too long");
8621d3294cSantirez SETARG_sBx(*jmp, offset);
8721d3294cSantirez }
8821d3294cSantirez
8921d3294cSantirez
9021d3294cSantirez /*
9121d3294cSantirez ** returns current `pc' and marks it as a jump target (to avoid wrong
9221d3294cSantirez ** optimizations with consecutive instructions not in the same basic block).
9321d3294cSantirez */
luaK_getlabel(FuncState * fs)9421d3294cSantirez int luaK_getlabel (FuncState *fs) {
9521d3294cSantirez fs->lasttarget = fs->pc;
9621d3294cSantirez return fs->pc;
9721d3294cSantirez }
9821d3294cSantirez
9921d3294cSantirez
getjump(FuncState * fs,int pc)10021d3294cSantirez static int getjump (FuncState *fs, int pc) {
10121d3294cSantirez int offset = GETARG_sBx(fs->f->code[pc]);
10221d3294cSantirez if (offset == NO_JUMP) /* point to itself represents end of list */
10321d3294cSantirez return NO_JUMP; /* end of list */
10421d3294cSantirez else
10521d3294cSantirez return (pc+1)+offset; /* turn offset into absolute position */
10621d3294cSantirez }
10721d3294cSantirez
10821d3294cSantirez
getjumpcontrol(FuncState * fs,int pc)10921d3294cSantirez static Instruction *getjumpcontrol (FuncState *fs, int pc) {
11021d3294cSantirez Instruction *pi = &fs->f->code[pc];
11121d3294cSantirez if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1))))
11221d3294cSantirez return pi-1;
11321d3294cSantirez else
11421d3294cSantirez return pi;
11521d3294cSantirez }
11621d3294cSantirez
11721d3294cSantirez
11821d3294cSantirez /*
11921d3294cSantirez ** check whether list has any jump that do not produce a value
12021d3294cSantirez ** (or produce an inverted value)
12121d3294cSantirez */
need_value(FuncState * fs,int list)12221d3294cSantirez static int need_value (FuncState *fs, int list) {
12321d3294cSantirez for (; list != NO_JUMP; list = getjump(fs, list)) {
12421d3294cSantirez Instruction i = *getjumpcontrol(fs, list);
12521d3294cSantirez if (GET_OPCODE(i) != OP_TESTSET) return 1;
12621d3294cSantirez }
12721d3294cSantirez return 0; /* not found */
12821d3294cSantirez }
12921d3294cSantirez
13021d3294cSantirez
patchtestreg(FuncState * fs,int node,int reg)13121d3294cSantirez static int patchtestreg (FuncState *fs, int node, int reg) {
13221d3294cSantirez Instruction *i = getjumpcontrol(fs, node);
13321d3294cSantirez if (GET_OPCODE(*i) != OP_TESTSET)
13421d3294cSantirez return 0; /* cannot patch other instructions */
13521d3294cSantirez if (reg != NO_REG && reg != GETARG_B(*i))
13621d3294cSantirez SETARG_A(*i, reg);
13721d3294cSantirez else /* no register to put value or register already has the value */
13821d3294cSantirez *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i));
13921d3294cSantirez
14021d3294cSantirez return 1;
14121d3294cSantirez }
14221d3294cSantirez
14321d3294cSantirez
removevalues(FuncState * fs,int list)14421d3294cSantirez static void removevalues (FuncState *fs, int list) {
14521d3294cSantirez for (; list != NO_JUMP; list = getjump(fs, list))
14621d3294cSantirez patchtestreg(fs, list, NO_REG);
14721d3294cSantirez }
14821d3294cSantirez
14921d3294cSantirez
patchlistaux(FuncState * fs,int list,int vtarget,int reg,int dtarget)15021d3294cSantirez static void patchlistaux (FuncState *fs, int list, int vtarget, int reg,
15121d3294cSantirez int dtarget) {
15221d3294cSantirez while (list != NO_JUMP) {
15321d3294cSantirez int next = getjump(fs, list);
15421d3294cSantirez if (patchtestreg(fs, list, reg))
15521d3294cSantirez fixjump(fs, list, vtarget);
15621d3294cSantirez else
15721d3294cSantirez fixjump(fs, list, dtarget); /* jump to default target */
15821d3294cSantirez list = next;
15921d3294cSantirez }
16021d3294cSantirez }
16121d3294cSantirez
16221d3294cSantirez
dischargejpc(FuncState * fs)16321d3294cSantirez static void dischargejpc (FuncState *fs) {
16421d3294cSantirez patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc);
16521d3294cSantirez fs->jpc = NO_JUMP;
16621d3294cSantirez }
16721d3294cSantirez
16821d3294cSantirez
luaK_patchlist(FuncState * fs,int list,int target)16921d3294cSantirez void luaK_patchlist (FuncState *fs, int list, int target) {
17021d3294cSantirez if (target == fs->pc)
17121d3294cSantirez luaK_patchtohere(fs, list);
17221d3294cSantirez else {
17321d3294cSantirez lua_assert(target < fs->pc);
17421d3294cSantirez patchlistaux(fs, list, target, NO_REG, target);
17521d3294cSantirez }
17621d3294cSantirez }
17721d3294cSantirez
17821d3294cSantirez
luaK_patchtohere(FuncState * fs,int list)17921d3294cSantirez void luaK_patchtohere (FuncState *fs, int list) {
18021d3294cSantirez luaK_getlabel(fs);
18121d3294cSantirez luaK_concat(fs, &fs->jpc, list);
18221d3294cSantirez }
18321d3294cSantirez
18421d3294cSantirez
luaK_concat(FuncState * fs,int * l1,int l2)18521d3294cSantirez void luaK_concat (FuncState *fs, int *l1, int l2) {
18621d3294cSantirez if (l2 == NO_JUMP) return;
18721d3294cSantirez else if (*l1 == NO_JUMP)
18821d3294cSantirez *l1 = l2;
18921d3294cSantirez else {
19021d3294cSantirez int list = *l1;
19121d3294cSantirez int next;
19221d3294cSantirez while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */
19321d3294cSantirez list = next;
19421d3294cSantirez fixjump(fs, list, l2);
19521d3294cSantirez }
19621d3294cSantirez }
19721d3294cSantirez
19821d3294cSantirez
luaK_checkstack(FuncState * fs,int n)19921d3294cSantirez void luaK_checkstack (FuncState *fs, int n) {
20021d3294cSantirez int newstack = fs->freereg + n;
20121d3294cSantirez if (newstack > fs->f->maxstacksize) {
20221d3294cSantirez if (newstack >= MAXSTACK)
20321d3294cSantirez luaX_syntaxerror(fs->ls, "function or expression too complex");
20421d3294cSantirez fs->f->maxstacksize = cast_byte(newstack);
20521d3294cSantirez }
20621d3294cSantirez }
20721d3294cSantirez
20821d3294cSantirez
luaK_reserveregs(FuncState * fs,int n)20921d3294cSantirez void luaK_reserveregs (FuncState *fs, int n) {
21021d3294cSantirez luaK_checkstack(fs, n);
21121d3294cSantirez fs->freereg += n;
21221d3294cSantirez }
21321d3294cSantirez
21421d3294cSantirez
freereg(FuncState * fs,int reg)21521d3294cSantirez static void freereg (FuncState *fs, int reg) {
21621d3294cSantirez if (!ISK(reg) && reg >= fs->nactvar) {
21721d3294cSantirez fs->freereg--;
21821d3294cSantirez lua_assert(reg == fs->freereg);
21921d3294cSantirez }
22021d3294cSantirez }
22121d3294cSantirez
22221d3294cSantirez
freeexp(FuncState * fs,expdesc * e)22321d3294cSantirez static void freeexp (FuncState *fs, expdesc *e) {
22421d3294cSantirez if (e->k == VNONRELOC)
22521d3294cSantirez freereg(fs, e->u.s.info);
22621d3294cSantirez }
22721d3294cSantirez
22821d3294cSantirez
addk(FuncState * fs,TValue * k,TValue * v)22921d3294cSantirez static int addk (FuncState *fs, TValue *k, TValue *v) {
23021d3294cSantirez lua_State *L = fs->L;
23121d3294cSantirez TValue *idx = luaH_set(L, fs->h, k);
23221d3294cSantirez Proto *f = fs->f;
23321d3294cSantirez int oldsize = f->sizek;
23421d3294cSantirez if (ttisnumber(idx)) {
23521d3294cSantirez lua_assert(luaO_rawequalObj(&fs->f->k[cast_int(nvalue(idx))], v));
23621d3294cSantirez return cast_int(nvalue(idx));
23721d3294cSantirez }
23821d3294cSantirez else { /* constant not found; create a new entry */
23921d3294cSantirez setnvalue(idx, cast_num(fs->nk));
24021d3294cSantirez luaM_growvector(L, f->k, fs->nk, f->sizek, TValue,
24121d3294cSantirez MAXARG_Bx, "constant table overflow");
24221d3294cSantirez while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]);
24321d3294cSantirez setobj(L, &f->k[fs->nk], v);
24421d3294cSantirez luaC_barrier(L, f, v);
24521d3294cSantirez return fs->nk++;
24621d3294cSantirez }
24721d3294cSantirez }
24821d3294cSantirez
24921d3294cSantirez
luaK_stringK(FuncState * fs,TString * s)25021d3294cSantirez int luaK_stringK (FuncState *fs, TString *s) {
25121d3294cSantirez TValue o;
25221d3294cSantirez setsvalue(fs->L, &o, s);
25321d3294cSantirez return addk(fs, &o, &o);
25421d3294cSantirez }
25521d3294cSantirez
25621d3294cSantirez
luaK_numberK(FuncState * fs,lua_Number r)25721d3294cSantirez int luaK_numberK (FuncState *fs, lua_Number r) {
25821d3294cSantirez TValue o;
25921d3294cSantirez setnvalue(&o, r);
26021d3294cSantirez return addk(fs, &o, &o);
26121d3294cSantirez }
26221d3294cSantirez
26321d3294cSantirez
boolK(FuncState * fs,int b)26421d3294cSantirez static int boolK (FuncState *fs, int b) {
26521d3294cSantirez TValue o;
26621d3294cSantirez setbvalue(&o, b);
26721d3294cSantirez return addk(fs, &o, &o);
26821d3294cSantirez }
26921d3294cSantirez
27021d3294cSantirez
nilK(FuncState * fs)27121d3294cSantirez static int nilK (FuncState *fs) {
27221d3294cSantirez TValue k, v;
27321d3294cSantirez setnilvalue(&v);
27421d3294cSantirez /* cannot use nil as key; instead use table itself to represent nil */
27521d3294cSantirez sethvalue(fs->L, &k, fs->h);
27621d3294cSantirez return addk(fs, &k, &v);
27721d3294cSantirez }
27821d3294cSantirez
27921d3294cSantirez
luaK_setreturns(FuncState * fs,expdesc * e,int nresults)28021d3294cSantirez void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) {
28121d3294cSantirez if (e->k == VCALL) { /* expression is an open function call? */
28221d3294cSantirez SETARG_C(getcode(fs, e), nresults+1);
28321d3294cSantirez }
28421d3294cSantirez else if (e->k == VVARARG) {
28521d3294cSantirez SETARG_B(getcode(fs, e), nresults+1);
28621d3294cSantirez SETARG_A(getcode(fs, e), fs->freereg);
28721d3294cSantirez luaK_reserveregs(fs, 1);
28821d3294cSantirez }
28921d3294cSantirez }
29021d3294cSantirez
29121d3294cSantirez
luaK_setoneret(FuncState * fs,expdesc * e)29221d3294cSantirez void luaK_setoneret (FuncState *fs, expdesc *e) {
29321d3294cSantirez if (e->k == VCALL) { /* expression is an open function call? */
29421d3294cSantirez e->k = VNONRELOC;
29521d3294cSantirez e->u.s.info = GETARG_A(getcode(fs, e));
29621d3294cSantirez }
29721d3294cSantirez else if (e->k == VVARARG) {
29821d3294cSantirez SETARG_B(getcode(fs, e), 2);
29921d3294cSantirez e->k = VRELOCABLE; /* can relocate its simple result */
30021d3294cSantirez }
30121d3294cSantirez }
30221d3294cSantirez
30321d3294cSantirez
luaK_dischargevars(FuncState * fs,expdesc * e)30421d3294cSantirez void luaK_dischargevars (FuncState *fs, expdesc *e) {
30521d3294cSantirez switch (e->k) {
30621d3294cSantirez case VLOCAL: {
30721d3294cSantirez e->k = VNONRELOC;
30821d3294cSantirez break;
30921d3294cSantirez }
31021d3294cSantirez case VUPVAL: {
31121d3294cSantirez e->u.s.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.s.info, 0);
31221d3294cSantirez e->k = VRELOCABLE;
31321d3294cSantirez break;
31421d3294cSantirez }
31521d3294cSantirez case VGLOBAL: {
31621d3294cSantirez e->u.s.info = luaK_codeABx(fs, OP_GETGLOBAL, 0, e->u.s.info);
31721d3294cSantirez e->k = VRELOCABLE;
31821d3294cSantirez break;
31921d3294cSantirez }
32021d3294cSantirez case VINDEXED: {
32121d3294cSantirez freereg(fs, e->u.s.aux);
32221d3294cSantirez freereg(fs, e->u.s.info);
32321d3294cSantirez e->u.s.info = luaK_codeABC(fs, OP_GETTABLE, 0, e->u.s.info, e->u.s.aux);
32421d3294cSantirez e->k = VRELOCABLE;
32521d3294cSantirez break;
32621d3294cSantirez }
32721d3294cSantirez case VVARARG:
32821d3294cSantirez case VCALL: {
32921d3294cSantirez luaK_setoneret(fs, e);
33021d3294cSantirez break;
33121d3294cSantirez }
33221d3294cSantirez default: break; /* there is one value available (somewhere) */
33321d3294cSantirez }
33421d3294cSantirez }
33521d3294cSantirez
33621d3294cSantirez
code_label(FuncState * fs,int A,int b,int jump)33721d3294cSantirez static int code_label (FuncState *fs, int A, int b, int jump) {
33821d3294cSantirez luaK_getlabel(fs); /* those instructions may be jump targets */
33921d3294cSantirez return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump);
34021d3294cSantirez }
34121d3294cSantirez
34221d3294cSantirez
discharge2reg(FuncState * fs,expdesc * e,int reg)34321d3294cSantirez static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
34421d3294cSantirez luaK_dischargevars(fs, e);
34521d3294cSantirez switch (e->k) {
34621d3294cSantirez case VNIL: {
34721d3294cSantirez luaK_nil(fs, reg, 1);
34821d3294cSantirez break;
34921d3294cSantirez }
35021d3294cSantirez case VFALSE: case VTRUE: {
35121d3294cSantirez luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0);
35221d3294cSantirez break;
35321d3294cSantirez }
35421d3294cSantirez case VK: {
35521d3294cSantirez luaK_codeABx(fs, OP_LOADK, reg, e->u.s.info);
35621d3294cSantirez break;
35721d3294cSantirez }
35821d3294cSantirez case VKNUM: {
35921d3294cSantirez luaK_codeABx(fs, OP_LOADK, reg, luaK_numberK(fs, e->u.nval));
36021d3294cSantirez break;
36121d3294cSantirez }
36221d3294cSantirez case VRELOCABLE: {
36321d3294cSantirez Instruction *pc = &getcode(fs, e);
36421d3294cSantirez SETARG_A(*pc, reg);
36521d3294cSantirez break;
36621d3294cSantirez }
36721d3294cSantirez case VNONRELOC: {
36821d3294cSantirez if (reg != e->u.s.info)
36921d3294cSantirez luaK_codeABC(fs, OP_MOVE, reg, e->u.s.info, 0);
37021d3294cSantirez break;
37121d3294cSantirez }
37221d3294cSantirez default: {
37321d3294cSantirez lua_assert(e->k == VVOID || e->k == VJMP);
37421d3294cSantirez return; /* nothing to do... */
37521d3294cSantirez }
37621d3294cSantirez }
37721d3294cSantirez e->u.s.info = reg;
37821d3294cSantirez e->k = VNONRELOC;
37921d3294cSantirez }
38021d3294cSantirez
38121d3294cSantirez
discharge2anyreg(FuncState * fs,expdesc * e)38221d3294cSantirez static void discharge2anyreg (FuncState *fs, expdesc *e) {
38321d3294cSantirez if (e->k != VNONRELOC) {
38421d3294cSantirez luaK_reserveregs(fs, 1);
38521d3294cSantirez discharge2reg(fs, e, fs->freereg-1);
38621d3294cSantirez }
38721d3294cSantirez }
38821d3294cSantirez
38921d3294cSantirez
exp2reg(FuncState * fs,expdesc * e,int reg)39021d3294cSantirez static void exp2reg (FuncState *fs, expdesc *e, int reg) {
39121d3294cSantirez discharge2reg(fs, e, reg);
39221d3294cSantirez if (e->k == VJMP)
39321d3294cSantirez luaK_concat(fs, &e->t, e->u.s.info); /* put this jump in `t' list */
39421d3294cSantirez if (hasjumps(e)) {
39521d3294cSantirez int final; /* position after whole expression */
39621d3294cSantirez int p_f = NO_JUMP; /* position of an eventual LOAD false */
39721d3294cSantirez int p_t = NO_JUMP; /* position of an eventual LOAD true */
39821d3294cSantirez if (need_value(fs, e->t) || need_value(fs, e->f)) {
39921d3294cSantirez int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs);
40021d3294cSantirez p_f = code_label(fs, reg, 0, 1);
40121d3294cSantirez p_t = code_label(fs, reg, 1, 0);
40221d3294cSantirez luaK_patchtohere(fs, fj);
40321d3294cSantirez }
40421d3294cSantirez final = luaK_getlabel(fs);
40521d3294cSantirez patchlistaux(fs, e->f, final, reg, p_f);
40621d3294cSantirez patchlistaux(fs, e->t, final, reg, p_t);
40721d3294cSantirez }
40821d3294cSantirez e->f = e->t = NO_JUMP;
40921d3294cSantirez e->u.s.info = reg;
41021d3294cSantirez e->k = VNONRELOC;
41121d3294cSantirez }
41221d3294cSantirez
41321d3294cSantirez
luaK_exp2nextreg(FuncState * fs,expdesc * e)41421d3294cSantirez void luaK_exp2nextreg (FuncState *fs, expdesc *e) {
41521d3294cSantirez luaK_dischargevars(fs, e);
41621d3294cSantirez freeexp(fs, e);
41721d3294cSantirez luaK_reserveregs(fs, 1);
41821d3294cSantirez exp2reg(fs, e, fs->freereg - 1);
41921d3294cSantirez }
42021d3294cSantirez
42121d3294cSantirez
luaK_exp2anyreg(FuncState * fs,expdesc * e)42221d3294cSantirez int luaK_exp2anyreg (FuncState *fs, expdesc *e) {
42321d3294cSantirez luaK_dischargevars(fs, e);
42421d3294cSantirez if (e->k == VNONRELOC) {
42521d3294cSantirez if (!hasjumps(e)) return e->u.s.info; /* exp is already in a register */
42621d3294cSantirez if (e->u.s.info >= fs->nactvar) { /* reg. is not a local? */
42721d3294cSantirez exp2reg(fs, e, e->u.s.info); /* put value on it */
42821d3294cSantirez return e->u.s.info;
42921d3294cSantirez }
43021d3294cSantirez }
43121d3294cSantirez luaK_exp2nextreg(fs, e); /* default */
43221d3294cSantirez return e->u.s.info;
43321d3294cSantirez }
43421d3294cSantirez
43521d3294cSantirez
luaK_exp2val(FuncState * fs,expdesc * e)43621d3294cSantirez void luaK_exp2val (FuncState *fs, expdesc *e) {
43721d3294cSantirez if (hasjumps(e))
43821d3294cSantirez luaK_exp2anyreg(fs, e);
43921d3294cSantirez else
44021d3294cSantirez luaK_dischargevars(fs, e);
44121d3294cSantirez }
44221d3294cSantirez
44321d3294cSantirez
luaK_exp2RK(FuncState * fs,expdesc * e)44421d3294cSantirez int luaK_exp2RK (FuncState *fs, expdesc *e) {
44521d3294cSantirez luaK_exp2val(fs, e);
44621d3294cSantirez switch (e->k) {
44721d3294cSantirez case VKNUM:
44821d3294cSantirez case VTRUE:
44921d3294cSantirez case VFALSE:
45021d3294cSantirez case VNIL: {
45121d3294cSantirez if (fs->nk <= MAXINDEXRK) { /* constant fit in RK operand? */
45221d3294cSantirez e->u.s.info = (e->k == VNIL) ? nilK(fs) :
45321d3294cSantirez (e->k == VKNUM) ? luaK_numberK(fs, e->u.nval) :
45421d3294cSantirez boolK(fs, (e->k == VTRUE));
45521d3294cSantirez e->k = VK;
45621d3294cSantirez return RKASK(e->u.s.info);
45721d3294cSantirez }
45821d3294cSantirez else break;
45921d3294cSantirez }
46021d3294cSantirez case VK: {
46121d3294cSantirez if (e->u.s.info <= MAXINDEXRK) /* constant fit in argC? */
46221d3294cSantirez return RKASK(e->u.s.info);
46321d3294cSantirez else break;
46421d3294cSantirez }
46521d3294cSantirez default: break;
46621d3294cSantirez }
46721d3294cSantirez /* not a constant in the right range: put it in a register */
46821d3294cSantirez return luaK_exp2anyreg(fs, e);
46921d3294cSantirez }
47021d3294cSantirez
47121d3294cSantirez
luaK_storevar(FuncState * fs,expdesc * var,expdesc * ex)47221d3294cSantirez void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
47321d3294cSantirez switch (var->k) {
47421d3294cSantirez case VLOCAL: {
47521d3294cSantirez freeexp(fs, ex);
47621d3294cSantirez exp2reg(fs, ex, var->u.s.info);
47721d3294cSantirez return;
47821d3294cSantirez }
47921d3294cSantirez case VUPVAL: {
48021d3294cSantirez int e = luaK_exp2anyreg(fs, ex);
48121d3294cSantirez luaK_codeABC(fs, OP_SETUPVAL, e, var->u.s.info, 0);
48221d3294cSantirez break;
48321d3294cSantirez }
48421d3294cSantirez case VGLOBAL: {
48521d3294cSantirez int e = luaK_exp2anyreg(fs, ex);
48621d3294cSantirez luaK_codeABx(fs, OP_SETGLOBAL, e, var->u.s.info);
48721d3294cSantirez break;
48821d3294cSantirez }
48921d3294cSantirez case VINDEXED: {
49021d3294cSantirez int e = luaK_exp2RK(fs, ex);
49121d3294cSantirez luaK_codeABC(fs, OP_SETTABLE, var->u.s.info, var->u.s.aux, e);
49221d3294cSantirez break;
49321d3294cSantirez }
49421d3294cSantirez default: {
49521d3294cSantirez lua_assert(0); /* invalid var kind to store */
49621d3294cSantirez break;
49721d3294cSantirez }
49821d3294cSantirez }
49921d3294cSantirez freeexp(fs, ex);
50021d3294cSantirez }
50121d3294cSantirez
50221d3294cSantirez
luaK_self(FuncState * fs,expdesc * e,expdesc * key)50321d3294cSantirez void luaK_self (FuncState *fs, expdesc *e, expdesc *key) {
50421d3294cSantirez int func;
50521d3294cSantirez luaK_exp2anyreg(fs, e);
50621d3294cSantirez freeexp(fs, e);
50721d3294cSantirez func = fs->freereg;
50821d3294cSantirez luaK_reserveregs(fs, 2);
50921d3294cSantirez luaK_codeABC(fs, OP_SELF, func, e->u.s.info, luaK_exp2RK(fs, key));
51021d3294cSantirez freeexp(fs, key);
51121d3294cSantirez e->u.s.info = func;
51221d3294cSantirez e->k = VNONRELOC;
51321d3294cSantirez }
51421d3294cSantirez
51521d3294cSantirez
invertjump(FuncState * fs,expdesc * e)51621d3294cSantirez static void invertjump (FuncState *fs, expdesc *e) {
51721d3294cSantirez Instruction *pc = getjumpcontrol(fs, e->u.s.info);
51821d3294cSantirez lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET &&
51921d3294cSantirez GET_OPCODE(*pc) != OP_TEST);
52021d3294cSantirez SETARG_A(*pc, !(GETARG_A(*pc)));
52121d3294cSantirez }
52221d3294cSantirez
52321d3294cSantirez
jumponcond(FuncState * fs,expdesc * e,int cond)52421d3294cSantirez static int jumponcond (FuncState *fs, expdesc *e, int cond) {
52521d3294cSantirez if (e->k == VRELOCABLE) {
52621d3294cSantirez Instruction ie = getcode(fs, e);
52721d3294cSantirez if (GET_OPCODE(ie) == OP_NOT) {
52821d3294cSantirez fs->pc--; /* remove previous OP_NOT */
52921d3294cSantirez return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond);
53021d3294cSantirez }
53121d3294cSantirez /* else go through */
53221d3294cSantirez }
53321d3294cSantirez discharge2anyreg(fs, e);
53421d3294cSantirez freeexp(fs, e);
53521d3294cSantirez return condjump(fs, OP_TESTSET, NO_REG, e->u.s.info, cond);
53621d3294cSantirez }
53721d3294cSantirez
53821d3294cSantirez
luaK_goiftrue(FuncState * fs,expdesc * e)53921d3294cSantirez void luaK_goiftrue (FuncState *fs, expdesc *e) {
54021d3294cSantirez int pc; /* pc of last jump */
54121d3294cSantirez luaK_dischargevars(fs, e);
54221d3294cSantirez switch (e->k) {
54321d3294cSantirez case VK: case VKNUM: case VTRUE: {
54421d3294cSantirez pc = NO_JUMP; /* always true; do nothing */
54521d3294cSantirez break;
54621d3294cSantirez }
54721d3294cSantirez case VJMP: {
54821d3294cSantirez invertjump(fs, e);
54921d3294cSantirez pc = e->u.s.info;
55021d3294cSantirez break;
55121d3294cSantirez }
55221d3294cSantirez default: {
55321d3294cSantirez pc = jumponcond(fs, e, 0);
55421d3294cSantirez break;
55521d3294cSantirez }
55621d3294cSantirez }
55721d3294cSantirez luaK_concat(fs, &e->f, pc); /* insert last jump in `f' list */
55821d3294cSantirez luaK_patchtohere(fs, e->t);
55921d3294cSantirez e->t = NO_JUMP;
56021d3294cSantirez }
56121d3294cSantirez
56221d3294cSantirez
luaK_goiffalse(FuncState * fs,expdesc * e)56321d3294cSantirez static void luaK_goiffalse (FuncState *fs, expdesc *e) {
56421d3294cSantirez int pc; /* pc of last jump */
56521d3294cSantirez luaK_dischargevars(fs, e);
56621d3294cSantirez switch (e->k) {
56721d3294cSantirez case VNIL: case VFALSE: {
56821d3294cSantirez pc = NO_JUMP; /* always false; do nothing */
56921d3294cSantirez break;
57021d3294cSantirez }
57121d3294cSantirez case VJMP: {
57221d3294cSantirez pc = e->u.s.info;
57321d3294cSantirez break;
57421d3294cSantirez }
57521d3294cSantirez default: {
57621d3294cSantirez pc = jumponcond(fs, e, 1);
57721d3294cSantirez break;
57821d3294cSantirez }
57921d3294cSantirez }
58021d3294cSantirez luaK_concat(fs, &e->t, pc); /* insert last jump in `t' list */
58121d3294cSantirez luaK_patchtohere(fs, e->f);
58221d3294cSantirez e->f = NO_JUMP;
58321d3294cSantirez }
58421d3294cSantirez
58521d3294cSantirez
codenot(FuncState * fs,expdesc * e)58621d3294cSantirez static void codenot (FuncState *fs, expdesc *e) {
58721d3294cSantirez luaK_dischargevars(fs, e);
58821d3294cSantirez switch (e->k) {
58921d3294cSantirez case VNIL: case VFALSE: {
59021d3294cSantirez e->k = VTRUE;
59121d3294cSantirez break;
59221d3294cSantirez }
59321d3294cSantirez case VK: case VKNUM: case VTRUE: {
59421d3294cSantirez e->k = VFALSE;
59521d3294cSantirez break;
59621d3294cSantirez }
59721d3294cSantirez case VJMP: {
59821d3294cSantirez invertjump(fs, e);
59921d3294cSantirez break;
60021d3294cSantirez }
60121d3294cSantirez case VRELOCABLE:
60221d3294cSantirez case VNONRELOC: {
60321d3294cSantirez discharge2anyreg(fs, e);
60421d3294cSantirez freeexp(fs, e);
60521d3294cSantirez e->u.s.info = luaK_codeABC(fs, OP_NOT, 0, e->u.s.info, 0);
60621d3294cSantirez e->k = VRELOCABLE;
60721d3294cSantirez break;
60821d3294cSantirez }
60921d3294cSantirez default: {
61021d3294cSantirez lua_assert(0); /* cannot happen */
61121d3294cSantirez break;
61221d3294cSantirez }
61321d3294cSantirez }
61421d3294cSantirez /* interchange true and false lists */
61521d3294cSantirez { int temp = e->f; e->f = e->t; e->t = temp; }
61621d3294cSantirez removevalues(fs, e->f);
61721d3294cSantirez removevalues(fs, e->t);
61821d3294cSantirez }
61921d3294cSantirez
62021d3294cSantirez
luaK_indexed(FuncState * fs,expdesc * t,expdesc * k)62121d3294cSantirez void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
62221d3294cSantirez t->u.s.aux = luaK_exp2RK(fs, k);
62321d3294cSantirez t->k = VINDEXED;
62421d3294cSantirez }
62521d3294cSantirez
62621d3294cSantirez
constfolding(OpCode op,expdesc * e1,expdesc * e2)62721d3294cSantirez static int constfolding (OpCode op, expdesc *e1, expdesc *e2) {
62821d3294cSantirez lua_Number v1, v2, r;
62921d3294cSantirez if (!isnumeral(e1) || !isnumeral(e2)) return 0;
63021d3294cSantirez v1 = e1->u.nval;
63121d3294cSantirez v2 = e2->u.nval;
63221d3294cSantirez switch (op) {
63321d3294cSantirez case OP_ADD: r = luai_numadd(v1, v2); break;
63421d3294cSantirez case OP_SUB: r = luai_numsub(v1, v2); break;
63521d3294cSantirez case OP_MUL: r = luai_nummul(v1, v2); break;
63621d3294cSantirez case OP_DIV:
63721d3294cSantirez if (v2 == 0) return 0; /* do not attempt to divide by 0 */
63821d3294cSantirez r = luai_numdiv(v1, v2); break;
63921d3294cSantirez case OP_MOD:
64021d3294cSantirez if (v2 == 0) return 0; /* do not attempt to divide by 0 */
64121d3294cSantirez r = luai_nummod(v1, v2); break;
64221d3294cSantirez case OP_POW: r = luai_numpow(v1, v2); break;
64321d3294cSantirez case OP_UNM: r = luai_numunm(v1); break;
64421d3294cSantirez case OP_LEN: return 0; /* no constant folding for 'len' */
64521d3294cSantirez default: lua_assert(0); r = 0; break;
64621d3294cSantirez }
64721d3294cSantirez if (luai_numisnan(r)) return 0; /* do not attempt to produce NaN */
64821d3294cSantirez e1->u.nval = r;
64921d3294cSantirez return 1;
65021d3294cSantirez }
65121d3294cSantirez
65221d3294cSantirez
codearith(FuncState * fs,OpCode op,expdesc * e1,expdesc * e2)65321d3294cSantirez static void codearith (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) {
65421d3294cSantirez if (constfolding(op, e1, e2))
65521d3294cSantirez return;
65621d3294cSantirez else {
65721d3294cSantirez int o2 = (op != OP_UNM && op != OP_LEN) ? luaK_exp2RK(fs, e2) : 0;
65821d3294cSantirez int o1 = luaK_exp2RK(fs, e1);
65921d3294cSantirez if (o1 > o2) {
66021d3294cSantirez freeexp(fs, e1);
66121d3294cSantirez freeexp(fs, e2);
66221d3294cSantirez }
66321d3294cSantirez else {
66421d3294cSantirez freeexp(fs, e2);
66521d3294cSantirez freeexp(fs, e1);
66621d3294cSantirez }
66721d3294cSantirez e1->u.s.info = luaK_codeABC(fs, op, 0, o1, o2);
66821d3294cSantirez e1->k = VRELOCABLE;
66921d3294cSantirez }
67021d3294cSantirez }
67121d3294cSantirez
67221d3294cSantirez
codecomp(FuncState * fs,OpCode op,int cond,expdesc * e1,expdesc * e2)67321d3294cSantirez static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1,
67421d3294cSantirez expdesc *e2) {
67521d3294cSantirez int o1 = luaK_exp2RK(fs, e1);
67621d3294cSantirez int o2 = luaK_exp2RK(fs, e2);
67721d3294cSantirez freeexp(fs, e2);
67821d3294cSantirez freeexp(fs, e1);
67921d3294cSantirez if (cond == 0 && op != OP_EQ) {
68021d3294cSantirez int temp; /* exchange args to replace by `<' or `<=' */
68121d3294cSantirez temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */
68221d3294cSantirez cond = 1;
68321d3294cSantirez }
68421d3294cSantirez e1->u.s.info = condjump(fs, op, cond, o1, o2);
68521d3294cSantirez e1->k = VJMP;
68621d3294cSantirez }
68721d3294cSantirez
68821d3294cSantirez
luaK_prefix(FuncState * fs,UnOpr op,expdesc * e)68921d3294cSantirez void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) {
69021d3294cSantirez expdesc e2;
69121d3294cSantirez e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0;
69221d3294cSantirez switch (op) {
69321d3294cSantirez case OPR_MINUS: {
69421d3294cSantirez if (!isnumeral(e))
69521d3294cSantirez luaK_exp2anyreg(fs, e); /* cannot operate on non-numeric constants */
69621d3294cSantirez codearith(fs, OP_UNM, e, &e2);
69721d3294cSantirez break;
69821d3294cSantirez }
69921d3294cSantirez case OPR_NOT: codenot(fs, e); break;
70021d3294cSantirez case OPR_LEN: {
70121d3294cSantirez luaK_exp2anyreg(fs, e); /* cannot operate on constants */
70221d3294cSantirez codearith(fs, OP_LEN, e, &e2);
70321d3294cSantirez break;
70421d3294cSantirez }
70521d3294cSantirez default: lua_assert(0);
70621d3294cSantirez }
70721d3294cSantirez }
70821d3294cSantirez
70921d3294cSantirez
luaK_infix(FuncState * fs,BinOpr op,expdesc * v)71021d3294cSantirez void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
71121d3294cSantirez switch (op) {
71221d3294cSantirez case OPR_AND: {
71321d3294cSantirez luaK_goiftrue(fs, v);
71421d3294cSantirez break;
71521d3294cSantirez }
71621d3294cSantirez case OPR_OR: {
71721d3294cSantirez luaK_goiffalse(fs, v);
71821d3294cSantirez break;
71921d3294cSantirez }
72021d3294cSantirez case OPR_CONCAT: {
72121d3294cSantirez luaK_exp2nextreg(fs, v); /* operand must be on the `stack' */
72221d3294cSantirez break;
72321d3294cSantirez }
72421d3294cSantirez case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV:
72521d3294cSantirez case OPR_MOD: case OPR_POW: {
72621d3294cSantirez if (!isnumeral(v)) luaK_exp2RK(fs, v);
72721d3294cSantirez break;
72821d3294cSantirez }
72921d3294cSantirez default: {
73021d3294cSantirez luaK_exp2RK(fs, v);
73121d3294cSantirez break;
73221d3294cSantirez }
73321d3294cSantirez }
73421d3294cSantirez }
73521d3294cSantirez
73621d3294cSantirez
luaK_posfix(FuncState * fs,BinOpr op,expdesc * e1,expdesc * e2)73721d3294cSantirez void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) {
73821d3294cSantirez switch (op) {
73921d3294cSantirez case OPR_AND: {
74021d3294cSantirez lua_assert(e1->t == NO_JUMP); /* list must be closed */
74121d3294cSantirez luaK_dischargevars(fs, e2);
74221d3294cSantirez luaK_concat(fs, &e2->f, e1->f);
74321d3294cSantirez *e1 = *e2;
74421d3294cSantirez break;
74521d3294cSantirez }
74621d3294cSantirez case OPR_OR: {
74721d3294cSantirez lua_assert(e1->f == NO_JUMP); /* list must be closed */
74821d3294cSantirez luaK_dischargevars(fs, e2);
74921d3294cSantirez luaK_concat(fs, &e2->t, e1->t);
75021d3294cSantirez *e1 = *e2;
75121d3294cSantirez break;
75221d3294cSantirez }
75321d3294cSantirez case OPR_CONCAT: {
75421d3294cSantirez luaK_exp2val(fs, e2);
75521d3294cSantirez if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) {
75621d3294cSantirez lua_assert(e1->u.s.info == GETARG_B(getcode(fs, e2))-1);
75721d3294cSantirez freeexp(fs, e1);
75821d3294cSantirez SETARG_B(getcode(fs, e2), e1->u.s.info);
75921d3294cSantirez e1->k = VRELOCABLE; e1->u.s.info = e2->u.s.info;
76021d3294cSantirez }
76121d3294cSantirez else {
76221d3294cSantirez luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */
76321d3294cSantirez codearith(fs, OP_CONCAT, e1, e2);
76421d3294cSantirez }
76521d3294cSantirez break;
76621d3294cSantirez }
76721d3294cSantirez case OPR_ADD: codearith(fs, OP_ADD, e1, e2); break;
76821d3294cSantirez case OPR_SUB: codearith(fs, OP_SUB, e1, e2); break;
76921d3294cSantirez case OPR_MUL: codearith(fs, OP_MUL, e1, e2); break;
77021d3294cSantirez case OPR_DIV: codearith(fs, OP_DIV, e1, e2); break;
77121d3294cSantirez case OPR_MOD: codearith(fs, OP_MOD, e1, e2); break;
77221d3294cSantirez case OPR_POW: codearith(fs, OP_POW, e1, e2); break;
77321d3294cSantirez case OPR_EQ: codecomp(fs, OP_EQ, 1, e1, e2); break;
77421d3294cSantirez case OPR_NE: codecomp(fs, OP_EQ, 0, e1, e2); break;
77521d3294cSantirez case OPR_LT: codecomp(fs, OP_LT, 1, e1, e2); break;
77621d3294cSantirez case OPR_LE: codecomp(fs, OP_LE, 1, e1, e2); break;
77721d3294cSantirez case OPR_GT: codecomp(fs, OP_LT, 0, e1, e2); break;
77821d3294cSantirez case OPR_GE: codecomp(fs, OP_LE, 0, e1, e2); break;
77921d3294cSantirez default: lua_assert(0);
78021d3294cSantirez }
78121d3294cSantirez }
78221d3294cSantirez
78321d3294cSantirez
luaK_fixline(FuncState * fs,int line)78421d3294cSantirez void luaK_fixline (FuncState *fs, int line) {
78521d3294cSantirez fs->f->lineinfo[fs->pc - 1] = line;
78621d3294cSantirez }
78721d3294cSantirez
78821d3294cSantirez
luaK_code(FuncState * fs,Instruction i,int line)78921d3294cSantirez static int luaK_code (FuncState *fs, Instruction i, int line) {
79021d3294cSantirez Proto *f = fs->f;
79121d3294cSantirez dischargejpc(fs); /* `pc' will change */
79221d3294cSantirez /* put new instruction in code array */
79321d3294cSantirez luaM_growvector(fs->L, f->code, fs->pc, f->sizecode, Instruction,
79421d3294cSantirez MAX_INT, "code size overflow");
79521d3294cSantirez f->code[fs->pc] = i;
79621d3294cSantirez /* save corresponding line information */
79721d3294cSantirez luaM_growvector(fs->L, f->lineinfo, fs->pc, f->sizelineinfo, int,
79821d3294cSantirez MAX_INT, "code size overflow");
79921d3294cSantirez f->lineinfo[fs->pc] = line;
80021d3294cSantirez return fs->pc++;
80121d3294cSantirez }
80221d3294cSantirez
80321d3294cSantirez
luaK_codeABC(FuncState * fs,OpCode o,int a,int b,int c)80421d3294cSantirez int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) {
80521d3294cSantirez lua_assert(getOpMode(o) == iABC);
80621d3294cSantirez lua_assert(getBMode(o) != OpArgN || b == 0);
80721d3294cSantirez lua_assert(getCMode(o) != OpArgN || c == 0);
80821d3294cSantirez return luaK_code(fs, CREATE_ABC(o, a, b, c), fs->ls->lastline);
80921d3294cSantirez }
81021d3294cSantirez
81121d3294cSantirez
luaK_codeABx(FuncState * fs,OpCode o,int a,unsigned int bc)81221d3294cSantirez int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) {
81321d3294cSantirez lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx);
81421d3294cSantirez lua_assert(getCMode(o) == OpArgN);
81521d3294cSantirez return luaK_code(fs, CREATE_ABx(o, a, bc), fs->ls->lastline);
81621d3294cSantirez }
81721d3294cSantirez
81821d3294cSantirez
luaK_setlist(FuncState * fs,int base,int nelems,int tostore)81921d3294cSantirez void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) {
82021d3294cSantirez int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1;
82121d3294cSantirez int b = (tostore == LUA_MULTRET) ? 0 : tostore;
82221d3294cSantirez lua_assert(tostore != 0);
82321d3294cSantirez if (c <= MAXARG_C)
82421d3294cSantirez luaK_codeABC(fs, OP_SETLIST, base, b, c);
82521d3294cSantirez else {
82621d3294cSantirez luaK_codeABC(fs, OP_SETLIST, base, b, 0);
82721d3294cSantirez luaK_code(fs, cast(Instruction, c), fs->ls->lastline);
82821d3294cSantirez }
82921d3294cSantirez fs->freereg = base + 1; /* free registers with list values */
83021d3294cSantirez }
83121d3294cSantirez
832