18e3e3a7aSWarner Losh /* 2e112e9d2SKyle Evans ** $Id: lcode.c,v 2.112.1.1 2017/04/19 17:20:42 roberto Exp $ 38e3e3a7aSWarner Losh ** Code generator for Lua 48e3e3a7aSWarner Losh ** See Copyright Notice in lua.h 58e3e3a7aSWarner Losh */ 68e3e3a7aSWarner Losh 78e3e3a7aSWarner Losh #define lcode_c 88e3e3a7aSWarner Losh #define LUA_CORE 98e3e3a7aSWarner Losh 108e3e3a7aSWarner Losh #include "lprefix.h" 118e3e3a7aSWarner Losh 128e3e3a7aSWarner Losh 138e3e3a7aSWarner Losh #include <math.h> 148e3e3a7aSWarner Losh #include <stdlib.h> 158e3e3a7aSWarner Losh 168e3e3a7aSWarner Losh #include "lua.h" 178e3e3a7aSWarner Losh 188e3e3a7aSWarner Losh #include "lcode.h" 198e3e3a7aSWarner Losh #include "ldebug.h" 208e3e3a7aSWarner Losh #include "ldo.h" 218e3e3a7aSWarner Losh #include "lgc.h" 228e3e3a7aSWarner Losh #include "llex.h" 238e3e3a7aSWarner Losh #include "lmem.h" 248e3e3a7aSWarner Losh #include "lobject.h" 258e3e3a7aSWarner Losh #include "lopcodes.h" 268e3e3a7aSWarner Losh #include "lparser.h" 278e3e3a7aSWarner Losh #include "lstring.h" 288e3e3a7aSWarner Losh #include "ltable.h" 298e3e3a7aSWarner Losh #include "lvm.h" 308e3e3a7aSWarner Losh 318e3e3a7aSWarner Losh 328e3e3a7aSWarner Losh /* Maximum number of registers in a Lua function (must fit in 8 bits) */ 338e3e3a7aSWarner Losh #define MAXREGS 255 348e3e3a7aSWarner Losh 358e3e3a7aSWarner Losh 368e3e3a7aSWarner Losh #define hasjumps(e) ((e)->t != (e)->f) 378e3e3a7aSWarner Losh 388e3e3a7aSWarner Losh 398e3e3a7aSWarner Losh /* 408e3e3a7aSWarner Losh ** If expression is a numeric constant, fills 'v' with its value 418e3e3a7aSWarner Losh ** and returns 1. Otherwise, returns 0. 428e3e3a7aSWarner Losh */ 438e3e3a7aSWarner Losh static int tonumeral(const expdesc *e, TValue *v) { 448e3e3a7aSWarner Losh if (hasjumps(e)) 458e3e3a7aSWarner Losh return 0; /* not a numeral */ 468e3e3a7aSWarner Losh switch (e->k) { 478e3e3a7aSWarner Losh case VKINT: 488e3e3a7aSWarner Losh if (v) setivalue(v, e->u.ival); 498e3e3a7aSWarner Losh return 1; 508e3e3a7aSWarner Losh case VKFLT: 518e3e3a7aSWarner Losh if (v) setfltvalue(v, e->u.nval); 528e3e3a7aSWarner Losh return 1; 538e3e3a7aSWarner Losh default: return 0; 548e3e3a7aSWarner Losh } 558e3e3a7aSWarner Losh } 568e3e3a7aSWarner Losh 578e3e3a7aSWarner Losh 588e3e3a7aSWarner Losh /* 598e3e3a7aSWarner Losh ** Create a OP_LOADNIL instruction, but try to optimize: if the previous 608e3e3a7aSWarner Losh ** instruction is also OP_LOADNIL and ranges are compatible, adjust 618e3e3a7aSWarner Losh ** range of previous instruction instead of emitting a new one. (For 628e3e3a7aSWarner Losh ** instance, 'local a; local b' will generate a single opcode.) 638e3e3a7aSWarner Losh */ 648e3e3a7aSWarner Losh void luaK_nil (FuncState *fs, int from, int n) { 658e3e3a7aSWarner Losh Instruction *previous; 668e3e3a7aSWarner Losh int l = from + n - 1; /* last register to set nil */ 678e3e3a7aSWarner Losh if (fs->pc > fs->lasttarget) { /* no jumps to current position? */ 688e3e3a7aSWarner Losh previous = &fs->f->code[fs->pc-1]; 698e3e3a7aSWarner Losh if (GET_OPCODE(*previous) == OP_LOADNIL) { /* previous is LOADNIL? */ 708e3e3a7aSWarner Losh int pfrom = GETARG_A(*previous); /* get previous range */ 718e3e3a7aSWarner Losh int pl = pfrom + GETARG_B(*previous); 728e3e3a7aSWarner Losh if ((pfrom <= from && from <= pl + 1) || 738e3e3a7aSWarner Losh (from <= pfrom && pfrom <= l + 1)) { /* can connect both? */ 748e3e3a7aSWarner Losh if (pfrom < from) from = pfrom; /* from = min(from, pfrom) */ 758e3e3a7aSWarner Losh if (pl > l) l = pl; /* l = max(l, pl) */ 768e3e3a7aSWarner Losh SETARG_A(*previous, from); 778e3e3a7aSWarner Losh SETARG_B(*previous, l - from); 788e3e3a7aSWarner Losh return; 798e3e3a7aSWarner Losh } 808e3e3a7aSWarner Losh } /* else go through */ 818e3e3a7aSWarner Losh } 828e3e3a7aSWarner Losh luaK_codeABC(fs, OP_LOADNIL, from, n - 1, 0); /* else no optimization */ 838e3e3a7aSWarner Losh } 848e3e3a7aSWarner Losh 858e3e3a7aSWarner Losh 868e3e3a7aSWarner Losh /* 878e3e3a7aSWarner Losh ** Gets the destination address of a jump instruction. Used to traverse 888e3e3a7aSWarner Losh ** a list of jumps. 898e3e3a7aSWarner Losh */ 908e3e3a7aSWarner Losh static int getjump (FuncState *fs, int pc) { 918e3e3a7aSWarner Losh int offset = GETARG_sBx(fs->f->code[pc]); 928e3e3a7aSWarner Losh if (offset == NO_JUMP) /* point to itself represents end of list */ 938e3e3a7aSWarner Losh return NO_JUMP; /* end of list */ 948e3e3a7aSWarner Losh else 958e3e3a7aSWarner Losh return (pc+1)+offset; /* turn offset into absolute position */ 968e3e3a7aSWarner Losh } 978e3e3a7aSWarner Losh 988e3e3a7aSWarner Losh 998e3e3a7aSWarner Losh /* 1008e3e3a7aSWarner Losh ** Fix jump instruction at position 'pc' to jump to 'dest'. 1018e3e3a7aSWarner Losh ** (Jump addresses are relative in Lua) 1028e3e3a7aSWarner Losh */ 1038e3e3a7aSWarner Losh static void fixjump (FuncState *fs, int pc, int dest) { 1048e3e3a7aSWarner Losh Instruction *jmp = &fs->f->code[pc]; 1058e3e3a7aSWarner Losh int offset = dest - (pc + 1); 1068e3e3a7aSWarner Losh lua_assert(dest != NO_JUMP); 1078e3e3a7aSWarner Losh if (abs(offset) > MAXARG_sBx) 1088e3e3a7aSWarner Losh luaX_syntaxerror(fs->ls, "control structure too long"); 1098e3e3a7aSWarner Losh SETARG_sBx(*jmp, offset); 1108e3e3a7aSWarner Losh } 1118e3e3a7aSWarner Losh 1128e3e3a7aSWarner Losh 1138e3e3a7aSWarner Losh /* 1148e3e3a7aSWarner Losh ** Concatenate jump-list 'l2' into jump-list 'l1' 1158e3e3a7aSWarner Losh */ 1168e3e3a7aSWarner Losh void luaK_concat (FuncState *fs, int *l1, int l2) { 1178e3e3a7aSWarner Losh if (l2 == NO_JUMP) return; /* nothing to concatenate? */ 1188e3e3a7aSWarner Losh else if (*l1 == NO_JUMP) /* no original list? */ 1198e3e3a7aSWarner Losh *l1 = l2; /* 'l1' points to 'l2' */ 1208e3e3a7aSWarner Losh else { 1218e3e3a7aSWarner Losh int list = *l1; 1228e3e3a7aSWarner Losh int next; 1238e3e3a7aSWarner Losh while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */ 1248e3e3a7aSWarner Losh list = next; 1258e3e3a7aSWarner Losh fixjump(fs, list, l2); /* last element links to 'l2' */ 1268e3e3a7aSWarner Losh } 1278e3e3a7aSWarner Losh } 1288e3e3a7aSWarner Losh 1298e3e3a7aSWarner Losh 1308e3e3a7aSWarner Losh /* 1318e3e3a7aSWarner Losh ** Create a jump instruction and return its position, so its destination 1328e3e3a7aSWarner Losh ** can be fixed later (with 'fixjump'). If there are jumps to 1338e3e3a7aSWarner Losh ** this position (kept in 'jpc'), link them all together so that 1348e3e3a7aSWarner Losh ** 'patchlistaux' will fix all them directly to the final destination. 1358e3e3a7aSWarner Losh */ 1368e3e3a7aSWarner Losh int luaK_jump (FuncState *fs) { 1378e3e3a7aSWarner Losh int jpc = fs->jpc; /* save list of jumps to here */ 1388e3e3a7aSWarner Losh int j; 1398e3e3a7aSWarner Losh fs->jpc = NO_JUMP; /* no more jumps to here */ 1408e3e3a7aSWarner Losh j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP); 1418e3e3a7aSWarner Losh luaK_concat(fs, &j, jpc); /* keep them on hold */ 1428e3e3a7aSWarner Losh return j; 1438e3e3a7aSWarner Losh } 1448e3e3a7aSWarner Losh 1458e3e3a7aSWarner Losh 1468e3e3a7aSWarner Losh /* 1478e3e3a7aSWarner Losh ** Code a 'return' instruction 1488e3e3a7aSWarner Losh */ 1498e3e3a7aSWarner Losh void luaK_ret (FuncState *fs, int first, int nret) { 1508e3e3a7aSWarner Losh luaK_codeABC(fs, OP_RETURN, first, nret+1, 0); 1518e3e3a7aSWarner Losh } 1528e3e3a7aSWarner Losh 1538e3e3a7aSWarner Losh 1548e3e3a7aSWarner Losh /* 1558e3e3a7aSWarner Losh ** Code a "conditional jump", that is, a test or comparison opcode 1568e3e3a7aSWarner Losh ** followed by a jump. Return jump position. 1578e3e3a7aSWarner Losh */ 1588e3e3a7aSWarner Losh static int condjump (FuncState *fs, OpCode op, int A, int B, int C) { 1598e3e3a7aSWarner Losh luaK_codeABC(fs, op, A, B, C); 1608e3e3a7aSWarner Losh return luaK_jump(fs); 1618e3e3a7aSWarner Losh } 1628e3e3a7aSWarner Losh 1638e3e3a7aSWarner Losh 1648e3e3a7aSWarner Losh /* 1658e3e3a7aSWarner Losh ** returns current 'pc' and marks it as a jump target (to avoid wrong 1668e3e3a7aSWarner Losh ** optimizations with consecutive instructions not in the same basic block). 1678e3e3a7aSWarner Losh */ 1688e3e3a7aSWarner Losh int luaK_getlabel (FuncState *fs) { 1698e3e3a7aSWarner Losh fs->lasttarget = fs->pc; 1708e3e3a7aSWarner Losh return fs->pc; 1718e3e3a7aSWarner Losh } 1728e3e3a7aSWarner Losh 1738e3e3a7aSWarner Losh 1748e3e3a7aSWarner Losh /* 1758e3e3a7aSWarner Losh ** Returns the position of the instruction "controlling" a given 1768e3e3a7aSWarner Losh ** jump (that is, its condition), or the jump itself if it is 1778e3e3a7aSWarner Losh ** unconditional. 1788e3e3a7aSWarner Losh */ 1798e3e3a7aSWarner Losh static Instruction *getjumpcontrol (FuncState *fs, int pc) { 1808e3e3a7aSWarner Losh Instruction *pi = &fs->f->code[pc]; 1818e3e3a7aSWarner Losh if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1)))) 1828e3e3a7aSWarner Losh return pi-1; 1838e3e3a7aSWarner Losh else 1848e3e3a7aSWarner Losh return pi; 1858e3e3a7aSWarner Losh } 1868e3e3a7aSWarner Losh 1878e3e3a7aSWarner Losh 1888e3e3a7aSWarner Losh /* 1898e3e3a7aSWarner Losh ** Patch destination register for a TESTSET instruction. 1908e3e3a7aSWarner Losh ** If instruction in position 'node' is not a TESTSET, return 0 ("fails"). 1918e3e3a7aSWarner Losh ** Otherwise, if 'reg' is not 'NO_REG', set it as the destination 1928e3e3a7aSWarner Losh ** register. Otherwise, change instruction to a simple 'TEST' (produces 1938e3e3a7aSWarner Losh ** no register value) 1948e3e3a7aSWarner Losh */ 1958e3e3a7aSWarner Losh static int patchtestreg (FuncState *fs, int node, int reg) { 1968e3e3a7aSWarner Losh Instruction *i = getjumpcontrol(fs, node); 1978e3e3a7aSWarner Losh if (GET_OPCODE(*i) != OP_TESTSET) 1988e3e3a7aSWarner Losh return 0; /* cannot patch other instructions */ 1998e3e3a7aSWarner Losh if (reg != NO_REG && reg != GETARG_B(*i)) 2008e3e3a7aSWarner Losh SETARG_A(*i, reg); 2018e3e3a7aSWarner Losh else { 2028e3e3a7aSWarner Losh /* no register to put value or register already has the value; 2038e3e3a7aSWarner Losh change instruction to simple test */ 2048e3e3a7aSWarner Losh *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i)); 2058e3e3a7aSWarner Losh } 2068e3e3a7aSWarner Losh return 1; 2078e3e3a7aSWarner Losh } 2088e3e3a7aSWarner Losh 2098e3e3a7aSWarner Losh 2108e3e3a7aSWarner Losh /* 2118e3e3a7aSWarner Losh ** Traverse a list of tests ensuring no one produces a value 2128e3e3a7aSWarner Losh */ 2138e3e3a7aSWarner Losh static void removevalues (FuncState *fs, int list) { 2148e3e3a7aSWarner Losh for (; list != NO_JUMP; list = getjump(fs, list)) 2158e3e3a7aSWarner Losh patchtestreg(fs, list, NO_REG); 2168e3e3a7aSWarner Losh } 2178e3e3a7aSWarner Losh 2188e3e3a7aSWarner Losh 2198e3e3a7aSWarner Losh /* 2208e3e3a7aSWarner Losh ** Traverse a list of tests, patching their destination address and 2218e3e3a7aSWarner Losh ** registers: tests producing values jump to 'vtarget' (and put their 2228e3e3a7aSWarner Losh ** values in 'reg'), other tests jump to 'dtarget'. 2238e3e3a7aSWarner Losh */ 2248e3e3a7aSWarner Losh static void patchlistaux (FuncState *fs, int list, int vtarget, int reg, 2258e3e3a7aSWarner Losh int dtarget) { 2268e3e3a7aSWarner Losh while (list != NO_JUMP) { 2278e3e3a7aSWarner Losh int next = getjump(fs, list); 2288e3e3a7aSWarner Losh if (patchtestreg(fs, list, reg)) 2298e3e3a7aSWarner Losh fixjump(fs, list, vtarget); 2308e3e3a7aSWarner Losh else 2318e3e3a7aSWarner Losh fixjump(fs, list, dtarget); /* jump to default target */ 2328e3e3a7aSWarner Losh list = next; 2338e3e3a7aSWarner Losh } 2348e3e3a7aSWarner Losh } 2358e3e3a7aSWarner Losh 2368e3e3a7aSWarner Losh 2378e3e3a7aSWarner Losh /* 2388e3e3a7aSWarner Losh ** Ensure all pending jumps to current position are fixed (jumping 2398e3e3a7aSWarner Losh ** to current position with no values) and reset list of pending 2408e3e3a7aSWarner Losh ** jumps 2418e3e3a7aSWarner Losh */ 2428e3e3a7aSWarner Losh static void dischargejpc (FuncState *fs) { 2438e3e3a7aSWarner Losh patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc); 2448e3e3a7aSWarner Losh fs->jpc = NO_JUMP; 2458e3e3a7aSWarner Losh } 2468e3e3a7aSWarner Losh 2478e3e3a7aSWarner Losh 2488e3e3a7aSWarner Losh /* 2498e3e3a7aSWarner Losh ** Add elements in 'list' to list of pending jumps to "here" 2508e3e3a7aSWarner Losh ** (current position) 2518e3e3a7aSWarner Losh */ 2528e3e3a7aSWarner Losh void luaK_patchtohere (FuncState *fs, int list) { 2538e3e3a7aSWarner Losh luaK_getlabel(fs); /* mark "here" as a jump target */ 2548e3e3a7aSWarner Losh luaK_concat(fs, &fs->jpc, list); 2558e3e3a7aSWarner Losh } 2568e3e3a7aSWarner Losh 2578e3e3a7aSWarner Losh 2588e3e3a7aSWarner Losh /* 2598e3e3a7aSWarner Losh ** Path all jumps in 'list' to jump to 'target'. 2608e3e3a7aSWarner Losh ** (The assert means that we cannot fix a jump to a forward address 2618e3e3a7aSWarner Losh ** because we only know addresses once code is generated.) 2628e3e3a7aSWarner Losh */ 2638e3e3a7aSWarner Losh void luaK_patchlist (FuncState *fs, int list, int target) { 2648e3e3a7aSWarner Losh if (target == fs->pc) /* 'target' is current position? */ 2658e3e3a7aSWarner Losh luaK_patchtohere(fs, list); /* add list to pending jumps */ 2668e3e3a7aSWarner Losh else { 2678e3e3a7aSWarner Losh lua_assert(target < fs->pc); 2688e3e3a7aSWarner Losh patchlistaux(fs, list, target, NO_REG, target); 2698e3e3a7aSWarner Losh } 2708e3e3a7aSWarner Losh } 2718e3e3a7aSWarner Losh 2728e3e3a7aSWarner Losh 2738e3e3a7aSWarner Losh /* 2748e3e3a7aSWarner Losh ** Path all jumps in 'list' to close upvalues up to given 'level' 2758e3e3a7aSWarner Losh ** (The assertion checks that jumps either were closing nothing 2768e3e3a7aSWarner Losh ** or were closing higher levels, from inner blocks.) 2778e3e3a7aSWarner Losh */ 2788e3e3a7aSWarner Losh void luaK_patchclose (FuncState *fs, int list, int level) { 2798e3e3a7aSWarner Losh level++; /* argument is +1 to reserve 0 as non-op */ 2808e3e3a7aSWarner Losh for (; list != NO_JUMP; list = getjump(fs, list)) { 2818e3e3a7aSWarner Losh lua_assert(GET_OPCODE(fs->f->code[list]) == OP_JMP && 2828e3e3a7aSWarner Losh (GETARG_A(fs->f->code[list]) == 0 || 2838e3e3a7aSWarner Losh GETARG_A(fs->f->code[list]) >= level)); 2848e3e3a7aSWarner Losh SETARG_A(fs->f->code[list], level); 2858e3e3a7aSWarner Losh } 2868e3e3a7aSWarner Losh } 2878e3e3a7aSWarner Losh 2888e3e3a7aSWarner Losh 2898e3e3a7aSWarner Losh /* 2908e3e3a7aSWarner Losh ** Emit instruction 'i', checking for array sizes and saving also its 2918e3e3a7aSWarner Losh ** line information. Return 'i' position. 2928e3e3a7aSWarner Losh */ 2938e3e3a7aSWarner Losh static int luaK_code (FuncState *fs, Instruction i) { 2948e3e3a7aSWarner Losh Proto *f = fs->f; 2958e3e3a7aSWarner Losh dischargejpc(fs); /* 'pc' will change */ 2968e3e3a7aSWarner Losh /* put new instruction in code array */ 2978e3e3a7aSWarner Losh luaM_growvector(fs->ls->L, f->code, fs->pc, f->sizecode, Instruction, 2988e3e3a7aSWarner Losh MAX_INT, "opcodes"); 2998e3e3a7aSWarner Losh f->code[fs->pc] = i; 3008e3e3a7aSWarner Losh /* save corresponding line information */ 3018e3e3a7aSWarner Losh luaM_growvector(fs->ls->L, f->lineinfo, fs->pc, f->sizelineinfo, int, 3028e3e3a7aSWarner Losh MAX_INT, "opcodes"); 3038e3e3a7aSWarner Losh f->lineinfo[fs->pc] = fs->ls->lastline; 3048e3e3a7aSWarner Losh return fs->pc++; 3058e3e3a7aSWarner Losh } 3068e3e3a7aSWarner Losh 3078e3e3a7aSWarner Losh 3088e3e3a7aSWarner Losh /* 3098e3e3a7aSWarner Losh ** Format and emit an 'iABC' instruction. (Assertions check consistency 3108e3e3a7aSWarner Losh ** of parameters versus opcode.) 3118e3e3a7aSWarner Losh */ 3128e3e3a7aSWarner Losh int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) { 3138e3e3a7aSWarner Losh lua_assert(getOpMode(o) == iABC); 3148e3e3a7aSWarner Losh lua_assert(getBMode(o) != OpArgN || b == 0); 3158e3e3a7aSWarner Losh lua_assert(getCMode(o) != OpArgN || c == 0); 3168e3e3a7aSWarner Losh lua_assert(a <= MAXARG_A && b <= MAXARG_B && c <= MAXARG_C); 3178e3e3a7aSWarner Losh return luaK_code(fs, CREATE_ABC(o, a, b, c)); 3188e3e3a7aSWarner Losh } 3198e3e3a7aSWarner Losh 3208e3e3a7aSWarner Losh 3218e3e3a7aSWarner Losh /* 3228e3e3a7aSWarner Losh ** Format and emit an 'iABx' instruction. 3238e3e3a7aSWarner Losh */ 3248e3e3a7aSWarner Losh int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) { 3258e3e3a7aSWarner Losh lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx); 3268e3e3a7aSWarner Losh lua_assert(getCMode(o) == OpArgN); 3278e3e3a7aSWarner Losh lua_assert(a <= MAXARG_A && bc <= MAXARG_Bx); 3288e3e3a7aSWarner Losh return luaK_code(fs, CREATE_ABx(o, a, bc)); 3298e3e3a7aSWarner Losh } 3308e3e3a7aSWarner Losh 3318e3e3a7aSWarner Losh 3328e3e3a7aSWarner Losh /* 3338e3e3a7aSWarner Losh ** Emit an "extra argument" instruction (format 'iAx') 3348e3e3a7aSWarner Losh */ 3358e3e3a7aSWarner Losh static int codeextraarg (FuncState *fs, int a) { 3368e3e3a7aSWarner Losh lua_assert(a <= MAXARG_Ax); 3378e3e3a7aSWarner Losh return luaK_code(fs, CREATE_Ax(OP_EXTRAARG, a)); 3388e3e3a7aSWarner Losh } 3398e3e3a7aSWarner Losh 3408e3e3a7aSWarner Losh 3418e3e3a7aSWarner Losh /* 3428e3e3a7aSWarner Losh ** Emit a "load constant" instruction, using either 'OP_LOADK' 3438e3e3a7aSWarner Losh ** (if constant index 'k' fits in 18 bits) or an 'OP_LOADKX' 3448e3e3a7aSWarner Losh ** instruction with "extra argument". 3458e3e3a7aSWarner Losh */ 3468e3e3a7aSWarner Losh int luaK_codek (FuncState *fs, int reg, int k) { 3478e3e3a7aSWarner Losh if (k <= MAXARG_Bx) 3488e3e3a7aSWarner Losh return luaK_codeABx(fs, OP_LOADK, reg, k); 3498e3e3a7aSWarner Losh else { 3508e3e3a7aSWarner Losh int p = luaK_codeABx(fs, OP_LOADKX, reg, 0); 3518e3e3a7aSWarner Losh codeextraarg(fs, k); 3528e3e3a7aSWarner Losh return p; 3538e3e3a7aSWarner Losh } 3548e3e3a7aSWarner Losh } 3558e3e3a7aSWarner Losh 3568e3e3a7aSWarner Losh 3578e3e3a7aSWarner Losh /* 3588e3e3a7aSWarner Losh ** Check register-stack level, keeping track of its maximum size 3598e3e3a7aSWarner Losh ** in field 'maxstacksize' 3608e3e3a7aSWarner Losh */ 3618e3e3a7aSWarner Losh void luaK_checkstack (FuncState *fs, int n) { 3628e3e3a7aSWarner Losh int newstack = fs->freereg + n; 3638e3e3a7aSWarner Losh if (newstack > fs->f->maxstacksize) { 3648e3e3a7aSWarner Losh if (newstack >= MAXREGS) 3658e3e3a7aSWarner Losh luaX_syntaxerror(fs->ls, 3668e3e3a7aSWarner Losh "function or expression needs too many registers"); 3678e3e3a7aSWarner Losh fs->f->maxstacksize = cast_byte(newstack); 3688e3e3a7aSWarner Losh } 3698e3e3a7aSWarner Losh } 3708e3e3a7aSWarner Losh 3718e3e3a7aSWarner Losh 3728e3e3a7aSWarner Losh /* 3738e3e3a7aSWarner Losh ** Reserve 'n' registers in register stack 3748e3e3a7aSWarner Losh */ 3758e3e3a7aSWarner Losh void luaK_reserveregs (FuncState *fs, int n) { 3768e3e3a7aSWarner Losh luaK_checkstack(fs, n); 3778e3e3a7aSWarner Losh fs->freereg += n; 3788e3e3a7aSWarner Losh } 3798e3e3a7aSWarner Losh 3808e3e3a7aSWarner Losh 3818e3e3a7aSWarner Losh /* 3828e3e3a7aSWarner Losh ** Free register 'reg', if it is neither a constant index nor 3838e3e3a7aSWarner Losh ** a local variable. 3848e3e3a7aSWarner Losh ) 3858e3e3a7aSWarner Losh */ 3868e3e3a7aSWarner Losh static void freereg (FuncState *fs, int reg) { 3878e3e3a7aSWarner Losh if (!ISK(reg) && reg >= fs->nactvar) { 3888e3e3a7aSWarner Losh fs->freereg--; 3898e3e3a7aSWarner Losh lua_assert(reg == fs->freereg); 3908e3e3a7aSWarner Losh } 3918e3e3a7aSWarner Losh } 3928e3e3a7aSWarner Losh 3938e3e3a7aSWarner Losh 3948e3e3a7aSWarner Losh /* 3958e3e3a7aSWarner Losh ** Free register used by expression 'e' (if any) 3968e3e3a7aSWarner Losh */ 3978e3e3a7aSWarner Losh static void freeexp (FuncState *fs, expdesc *e) { 3988e3e3a7aSWarner Losh if (e->k == VNONRELOC) 3998e3e3a7aSWarner Losh freereg(fs, e->u.info); 4008e3e3a7aSWarner Losh } 4018e3e3a7aSWarner Losh 4028e3e3a7aSWarner Losh 4038e3e3a7aSWarner Losh /* 4048e3e3a7aSWarner Losh ** Free registers used by expressions 'e1' and 'e2' (if any) in proper 4058e3e3a7aSWarner Losh ** order. 4068e3e3a7aSWarner Losh */ 4078e3e3a7aSWarner Losh static void freeexps (FuncState *fs, expdesc *e1, expdesc *e2) { 4088e3e3a7aSWarner Losh int r1 = (e1->k == VNONRELOC) ? e1->u.info : -1; 4098e3e3a7aSWarner Losh int r2 = (e2->k == VNONRELOC) ? e2->u.info : -1; 4108e3e3a7aSWarner Losh if (r1 > r2) { 4118e3e3a7aSWarner Losh freereg(fs, r1); 4128e3e3a7aSWarner Losh freereg(fs, r2); 4138e3e3a7aSWarner Losh } 4148e3e3a7aSWarner Losh else { 4158e3e3a7aSWarner Losh freereg(fs, r2); 4168e3e3a7aSWarner Losh freereg(fs, r1); 4178e3e3a7aSWarner Losh } 4188e3e3a7aSWarner Losh } 4198e3e3a7aSWarner Losh 4208e3e3a7aSWarner Losh 4218e3e3a7aSWarner Losh /* 4228e3e3a7aSWarner Losh ** Add constant 'v' to prototype's list of constants (field 'k'). 4238e3e3a7aSWarner Losh ** Use scanner's table to cache position of constants in constant list 4248e3e3a7aSWarner Losh ** and try to reuse constants. Because some values should not be used 4258e3e3a7aSWarner Losh ** as keys (nil cannot be a key, integer keys can collapse with float 4268e3e3a7aSWarner Losh ** keys), the caller must provide a useful 'key' for indexing the cache. 4278e3e3a7aSWarner Losh */ 4288e3e3a7aSWarner Losh static int addk (FuncState *fs, TValue *key, TValue *v) { 4298e3e3a7aSWarner Losh lua_State *L = fs->ls->L; 4308e3e3a7aSWarner Losh Proto *f = fs->f; 4318e3e3a7aSWarner Losh TValue *idx = luaH_set(L, fs->ls->h, key); /* index scanner table */ 4328e3e3a7aSWarner Losh int k, oldsize; 4338e3e3a7aSWarner Losh if (ttisinteger(idx)) { /* is there an index there? */ 4348e3e3a7aSWarner Losh k = cast_int(ivalue(idx)); 4358e3e3a7aSWarner Losh /* correct value? (warning: must distinguish floats from integers!) */ 4368e3e3a7aSWarner Losh if (k < fs->nk && ttype(&f->k[k]) == ttype(v) && 4378e3e3a7aSWarner Losh luaV_rawequalobj(&f->k[k], v)) 4388e3e3a7aSWarner Losh return k; /* reuse index */ 4398e3e3a7aSWarner Losh } 4408e3e3a7aSWarner Losh /* constant not found; create a new entry */ 4418e3e3a7aSWarner Losh oldsize = f->sizek; 4428e3e3a7aSWarner Losh k = fs->nk; 4438e3e3a7aSWarner Losh /* numerical value does not need GC barrier; 4448e3e3a7aSWarner Losh table has no metatable, so it does not need to invalidate cache */ 4458e3e3a7aSWarner Losh setivalue(idx, k); 4468e3e3a7aSWarner Losh luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants"); 4478e3e3a7aSWarner Losh while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); 4488e3e3a7aSWarner Losh setobj(L, &f->k[k], v); 4498e3e3a7aSWarner Losh fs->nk++; 4508e3e3a7aSWarner Losh luaC_barrier(L, f, v); 4518e3e3a7aSWarner Losh return k; 4528e3e3a7aSWarner Losh } 4538e3e3a7aSWarner Losh 4548e3e3a7aSWarner Losh 4558e3e3a7aSWarner Losh /* 4568e3e3a7aSWarner Losh ** Add a string to list of constants and return its index. 4578e3e3a7aSWarner Losh */ 4588e3e3a7aSWarner Losh int luaK_stringK (FuncState *fs, TString *s) { 4598e3e3a7aSWarner Losh TValue o; 4608e3e3a7aSWarner Losh setsvalue(fs->ls->L, &o, s); 4618e3e3a7aSWarner Losh return addk(fs, &o, &o); /* use string itself as key */ 4628e3e3a7aSWarner Losh } 4638e3e3a7aSWarner Losh 4648e3e3a7aSWarner Losh 4658e3e3a7aSWarner Losh /* 4668e3e3a7aSWarner Losh ** Add an integer to list of constants and return its index. 4678e3e3a7aSWarner Losh ** Integers use userdata as keys to avoid collision with floats with 4688e3e3a7aSWarner Losh ** same value; conversion to 'void*' is used only for hashing, so there 4698e3e3a7aSWarner Losh ** are no "precision" problems. 4708e3e3a7aSWarner Losh */ 4718e3e3a7aSWarner Losh int luaK_intK (FuncState *fs, lua_Integer n) { 4728e3e3a7aSWarner Losh TValue k, o; 4738e3e3a7aSWarner Losh setpvalue(&k, cast(void*, cast(size_t, n))); 4748e3e3a7aSWarner Losh setivalue(&o, n); 4758e3e3a7aSWarner Losh return addk(fs, &k, &o); 4768e3e3a7aSWarner Losh } 4778e3e3a7aSWarner Losh 4788e3e3a7aSWarner Losh /* 4798e3e3a7aSWarner Losh ** Add a float to list of constants and return its index. 4808e3e3a7aSWarner Losh */ 4818e3e3a7aSWarner Losh static int luaK_numberK (FuncState *fs, lua_Number r) { 4828e3e3a7aSWarner Losh TValue o; 4838e3e3a7aSWarner Losh setfltvalue(&o, r); 4848e3e3a7aSWarner Losh return addk(fs, &o, &o); /* use number itself as key */ 4858e3e3a7aSWarner Losh } 4868e3e3a7aSWarner Losh 4878e3e3a7aSWarner Losh 4888e3e3a7aSWarner Losh /* 4898e3e3a7aSWarner Losh ** Add a boolean to list of constants and return its index. 4908e3e3a7aSWarner Losh */ 4918e3e3a7aSWarner Losh static int boolK (FuncState *fs, int b) { 4928e3e3a7aSWarner Losh TValue o; 4938e3e3a7aSWarner Losh setbvalue(&o, b); 4948e3e3a7aSWarner Losh return addk(fs, &o, &o); /* use boolean itself as key */ 4958e3e3a7aSWarner Losh } 4968e3e3a7aSWarner Losh 4978e3e3a7aSWarner Losh 4988e3e3a7aSWarner Losh /* 4998e3e3a7aSWarner Losh ** Add nil to list of constants and return its index. 5008e3e3a7aSWarner Losh */ 5018e3e3a7aSWarner Losh static int nilK (FuncState *fs) { 5028e3e3a7aSWarner Losh TValue k, v; 5038e3e3a7aSWarner Losh setnilvalue(&v); 5048e3e3a7aSWarner Losh /* cannot use nil as key; instead use table itself to represent nil */ 5058e3e3a7aSWarner Losh sethvalue(fs->ls->L, &k, fs->ls->h); 5068e3e3a7aSWarner Losh return addk(fs, &k, &v); 5078e3e3a7aSWarner Losh } 5088e3e3a7aSWarner Losh 5098e3e3a7aSWarner Losh 5108e3e3a7aSWarner Losh /* 5118e3e3a7aSWarner Losh ** Fix an expression to return the number of results 'nresults'. 5128e3e3a7aSWarner Losh ** Either 'e' is a multi-ret expression (function call or vararg) 5138e3e3a7aSWarner Losh ** or 'nresults' is LUA_MULTRET (as any expression can satisfy that). 5148e3e3a7aSWarner Losh */ 5158e3e3a7aSWarner Losh void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) { 5168e3e3a7aSWarner Losh if (e->k == VCALL) { /* expression is an open function call? */ 5178e3e3a7aSWarner Losh SETARG_C(getinstruction(fs, e), nresults + 1); 5188e3e3a7aSWarner Losh } 5198e3e3a7aSWarner Losh else if (e->k == VVARARG) { 5208e3e3a7aSWarner Losh Instruction *pc = &getinstruction(fs, e); 5218e3e3a7aSWarner Losh SETARG_B(*pc, nresults + 1); 5228e3e3a7aSWarner Losh SETARG_A(*pc, fs->freereg); 5238e3e3a7aSWarner Losh luaK_reserveregs(fs, 1); 5248e3e3a7aSWarner Losh } 5258e3e3a7aSWarner Losh else lua_assert(nresults == LUA_MULTRET); 5268e3e3a7aSWarner Losh } 5278e3e3a7aSWarner Losh 5288e3e3a7aSWarner Losh 5298e3e3a7aSWarner Losh /* 5308e3e3a7aSWarner Losh ** Fix an expression to return one result. 5318e3e3a7aSWarner Losh ** If expression is not a multi-ret expression (function call or 5328e3e3a7aSWarner Losh ** vararg), it already returns one result, so nothing needs to be done. 5338e3e3a7aSWarner Losh ** Function calls become VNONRELOC expressions (as its result comes 5348e3e3a7aSWarner Losh ** fixed in the base register of the call), while vararg expressions 5358e3e3a7aSWarner Losh ** become VRELOCABLE (as OP_VARARG puts its results where it wants). 5368e3e3a7aSWarner Losh ** (Calls are created returning one result, so that does not need 5378e3e3a7aSWarner Losh ** to be fixed.) 5388e3e3a7aSWarner Losh */ 5398e3e3a7aSWarner Losh void luaK_setoneret (FuncState *fs, expdesc *e) { 5408e3e3a7aSWarner Losh if (e->k == VCALL) { /* expression is an open function call? */ 5418e3e3a7aSWarner Losh /* already returns 1 value */ 5428e3e3a7aSWarner Losh lua_assert(GETARG_C(getinstruction(fs, e)) == 2); 5438e3e3a7aSWarner Losh e->k = VNONRELOC; /* result has fixed position */ 5448e3e3a7aSWarner Losh e->u.info = GETARG_A(getinstruction(fs, e)); 5458e3e3a7aSWarner Losh } 5468e3e3a7aSWarner Losh else if (e->k == VVARARG) { 5478e3e3a7aSWarner Losh SETARG_B(getinstruction(fs, e), 2); 5488e3e3a7aSWarner Losh e->k = VRELOCABLE; /* can relocate its simple result */ 5498e3e3a7aSWarner Losh } 5508e3e3a7aSWarner Losh } 5518e3e3a7aSWarner Losh 5528e3e3a7aSWarner Losh 5538e3e3a7aSWarner Losh /* 5548e3e3a7aSWarner Losh ** Ensure that expression 'e' is not a variable. 5558e3e3a7aSWarner Losh */ 5568e3e3a7aSWarner Losh void luaK_dischargevars (FuncState *fs, expdesc *e) { 5578e3e3a7aSWarner Losh switch (e->k) { 5588e3e3a7aSWarner Losh case VLOCAL: { /* already in a register */ 5598e3e3a7aSWarner Losh e->k = VNONRELOC; /* becomes a non-relocatable value */ 5608e3e3a7aSWarner Losh break; 5618e3e3a7aSWarner Losh } 5628e3e3a7aSWarner Losh case VUPVAL: { /* move value to some (pending) register */ 5638e3e3a7aSWarner Losh e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0); 5648e3e3a7aSWarner Losh e->k = VRELOCABLE; 5658e3e3a7aSWarner Losh break; 5668e3e3a7aSWarner Losh } 5678e3e3a7aSWarner Losh case VINDEXED: { 5688e3e3a7aSWarner Losh OpCode op; 5698e3e3a7aSWarner Losh freereg(fs, e->u.ind.idx); 5708e3e3a7aSWarner Losh if (e->u.ind.vt == VLOCAL) { /* is 't' in a register? */ 5718e3e3a7aSWarner Losh freereg(fs, e->u.ind.t); 5728e3e3a7aSWarner Losh op = OP_GETTABLE; 5738e3e3a7aSWarner Losh } 5748e3e3a7aSWarner Losh else { 5758e3e3a7aSWarner Losh lua_assert(e->u.ind.vt == VUPVAL); 5768e3e3a7aSWarner Losh op = OP_GETTABUP; /* 't' is in an upvalue */ 5778e3e3a7aSWarner Losh } 5788e3e3a7aSWarner Losh e->u.info = luaK_codeABC(fs, op, 0, e->u.ind.t, e->u.ind.idx); 5798e3e3a7aSWarner Losh e->k = VRELOCABLE; 5808e3e3a7aSWarner Losh break; 5818e3e3a7aSWarner Losh } 5828e3e3a7aSWarner Losh case VVARARG: case VCALL: { 5838e3e3a7aSWarner Losh luaK_setoneret(fs, e); 5848e3e3a7aSWarner Losh break; 5858e3e3a7aSWarner Losh } 5868e3e3a7aSWarner Losh default: break; /* there is one value available (somewhere) */ 5878e3e3a7aSWarner Losh } 5888e3e3a7aSWarner Losh } 5898e3e3a7aSWarner Losh 5908e3e3a7aSWarner Losh 5918e3e3a7aSWarner Losh /* 5928e3e3a7aSWarner Losh ** Ensures expression value is in register 'reg' (and therefore 5938e3e3a7aSWarner Losh ** 'e' will become a non-relocatable expression). 5948e3e3a7aSWarner Losh */ 5958e3e3a7aSWarner Losh static void discharge2reg (FuncState *fs, expdesc *e, int reg) { 5968e3e3a7aSWarner Losh luaK_dischargevars(fs, e); 5978e3e3a7aSWarner Losh switch (e->k) { 5988e3e3a7aSWarner Losh case VNIL: { 5998e3e3a7aSWarner Losh luaK_nil(fs, reg, 1); 6008e3e3a7aSWarner Losh break; 6018e3e3a7aSWarner Losh } 6028e3e3a7aSWarner Losh case VFALSE: case VTRUE: { 6038e3e3a7aSWarner Losh luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0); 6048e3e3a7aSWarner Losh break; 6058e3e3a7aSWarner Losh } 6068e3e3a7aSWarner Losh case VK: { 6078e3e3a7aSWarner Losh luaK_codek(fs, reg, e->u.info); 6088e3e3a7aSWarner Losh break; 6098e3e3a7aSWarner Losh } 6108e3e3a7aSWarner Losh case VKFLT: { 6118e3e3a7aSWarner Losh luaK_codek(fs, reg, luaK_numberK(fs, e->u.nval)); 6128e3e3a7aSWarner Losh break; 6138e3e3a7aSWarner Losh } 6148e3e3a7aSWarner Losh case VKINT: { 6158e3e3a7aSWarner Losh luaK_codek(fs, reg, luaK_intK(fs, e->u.ival)); 6168e3e3a7aSWarner Losh break; 6178e3e3a7aSWarner Losh } 6188e3e3a7aSWarner Losh case VRELOCABLE: { 6198e3e3a7aSWarner Losh Instruction *pc = &getinstruction(fs, e); 6208e3e3a7aSWarner Losh SETARG_A(*pc, reg); /* instruction will put result in 'reg' */ 6218e3e3a7aSWarner Losh break; 6228e3e3a7aSWarner Losh } 6238e3e3a7aSWarner Losh case VNONRELOC: { 6248e3e3a7aSWarner Losh if (reg != e->u.info) 6258e3e3a7aSWarner Losh luaK_codeABC(fs, OP_MOVE, reg, e->u.info, 0); 6268e3e3a7aSWarner Losh break; 6278e3e3a7aSWarner Losh } 6288e3e3a7aSWarner Losh default: { 6298e3e3a7aSWarner Losh lua_assert(e->k == VJMP); 6308e3e3a7aSWarner Losh return; /* nothing to do... */ 6318e3e3a7aSWarner Losh } 6328e3e3a7aSWarner Losh } 6338e3e3a7aSWarner Losh e->u.info = reg; 6348e3e3a7aSWarner Losh e->k = VNONRELOC; 6358e3e3a7aSWarner Losh } 6368e3e3a7aSWarner Losh 6378e3e3a7aSWarner Losh 6388e3e3a7aSWarner Losh /* 6398e3e3a7aSWarner Losh ** Ensures expression value is in any register. 6408e3e3a7aSWarner Losh */ 6418e3e3a7aSWarner Losh static void discharge2anyreg (FuncState *fs, expdesc *e) { 6428e3e3a7aSWarner Losh if (e->k != VNONRELOC) { /* no fixed register yet? */ 6438e3e3a7aSWarner Losh luaK_reserveregs(fs, 1); /* get a register */ 6448e3e3a7aSWarner Losh discharge2reg(fs, e, fs->freereg-1); /* put value there */ 6458e3e3a7aSWarner Losh } 6468e3e3a7aSWarner Losh } 6478e3e3a7aSWarner Losh 6488e3e3a7aSWarner Losh 6498e3e3a7aSWarner Losh static int code_loadbool (FuncState *fs, int A, int b, int jump) { 6508e3e3a7aSWarner Losh luaK_getlabel(fs); /* those instructions may be jump targets */ 6518e3e3a7aSWarner Losh return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump); 6528e3e3a7aSWarner Losh } 6538e3e3a7aSWarner Losh 6548e3e3a7aSWarner Losh 6558e3e3a7aSWarner Losh /* 6568e3e3a7aSWarner Losh ** check whether list has any jump that do not produce a value 6578e3e3a7aSWarner Losh ** or produce an inverted value 6588e3e3a7aSWarner Losh */ 6598e3e3a7aSWarner Losh static int need_value (FuncState *fs, int list) { 6608e3e3a7aSWarner Losh for (; list != NO_JUMP; list = getjump(fs, list)) { 6618e3e3a7aSWarner Losh Instruction i = *getjumpcontrol(fs, list); 6628e3e3a7aSWarner Losh if (GET_OPCODE(i) != OP_TESTSET) return 1; 6638e3e3a7aSWarner Losh } 6648e3e3a7aSWarner Losh return 0; /* not found */ 6658e3e3a7aSWarner Losh } 6668e3e3a7aSWarner Losh 6678e3e3a7aSWarner Losh 6688e3e3a7aSWarner Losh /* 6698e3e3a7aSWarner Losh ** Ensures final expression result (including results from its jump 6708e3e3a7aSWarner Losh ** lists) is in register 'reg'. 6718e3e3a7aSWarner Losh ** If expression has jumps, need to patch these jumps either to 6728e3e3a7aSWarner Losh ** its final position or to "load" instructions (for those tests 6738e3e3a7aSWarner Losh ** that do not produce values). 6748e3e3a7aSWarner Losh */ 6758e3e3a7aSWarner Losh static void exp2reg (FuncState *fs, expdesc *e, int reg) { 6768e3e3a7aSWarner Losh discharge2reg(fs, e, reg); 6778e3e3a7aSWarner Losh if (e->k == VJMP) /* expression itself is a test? */ 6788e3e3a7aSWarner Losh luaK_concat(fs, &e->t, e->u.info); /* put this jump in 't' list */ 6798e3e3a7aSWarner Losh if (hasjumps(e)) { 6808e3e3a7aSWarner Losh int final; /* position after whole expression */ 6818e3e3a7aSWarner Losh int p_f = NO_JUMP; /* position of an eventual LOAD false */ 6828e3e3a7aSWarner Losh int p_t = NO_JUMP; /* position of an eventual LOAD true */ 6838e3e3a7aSWarner Losh if (need_value(fs, e->t) || need_value(fs, e->f)) { 6848e3e3a7aSWarner Losh int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs); 6858e3e3a7aSWarner Losh p_f = code_loadbool(fs, reg, 0, 1); 6868e3e3a7aSWarner Losh p_t = code_loadbool(fs, reg, 1, 0); 6878e3e3a7aSWarner Losh luaK_patchtohere(fs, fj); 6888e3e3a7aSWarner Losh } 6898e3e3a7aSWarner Losh final = luaK_getlabel(fs); 6908e3e3a7aSWarner Losh patchlistaux(fs, e->f, final, reg, p_f); 6918e3e3a7aSWarner Losh patchlistaux(fs, e->t, final, reg, p_t); 6928e3e3a7aSWarner Losh } 6938e3e3a7aSWarner Losh e->f = e->t = NO_JUMP; 6948e3e3a7aSWarner Losh e->u.info = reg; 6958e3e3a7aSWarner Losh e->k = VNONRELOC; 6968e3e3a7aSWarner Losh } 6978e3e3a7aSWarner Losh 6988e3e3a7aSWarner Losh 6998e3e3a7aSWarner Losh /* 7008e3e3a7aSWarner Losh ** Ensures final expression result (including results from its jump 7018e3e3a7aSWarner Losh ** lists) is in next available register. 7028e3e3a7aSWarner Losh */ 7038e3e3a7aSWarner Losh void luaK_exp2nextreg (FuncState *fs, expdesc *e) { 7048e3e3a7aSWarner Losh luaK_dischargevars(fs, e); 7058e3e3a7aSWarner Losh freeexp(fs, e); 7068e3e3a7aSWarner Losh luaK_reserveregs(fs, 1); 7078e3e3a7aSWarner Losh exp2reg(fs, e, fs->freereg - 1); 7088e3e3a7aSWarner Losh } 7098e3e3a7aSWarner Losh 7108e3e3a7aSWarner Losh 7118e3e3a7aSWarner Losh /* 7128e3e3a7aSWarner Losh ** Ensures final expression result (including results from its jump 7138e3e3a7aSWarner Losh ** lists) is in some (any) register and return that register. 7148e3e3a7aSWarner Losh */ 7158e3e3a7aSWarner Losh int luaK_exp2anyreg (FuncState *fs, expdesc *e) { 7168e3e3a7aSWarner Losh luaK_dischargevars(fs, e); 7178e3e3a7aSWarner Losh if (e->k == VNONRELOC) { /* expression already has a register? */ 7188e3e3a7aSWarner Losh if (!hasjumps(e)) /* no jumps? */ 7198e3e3a7aSWarner Losh return e->u.info; /* result is already in a register */ 7208e3e3a7aSWarner Losh if (e->u.info >= fs->nactvar) { /* reg. is not a local? */ 7218e3e3a7aSWarner Losh exp2reg(fs, e, e->u.info); /* put final result in it */ 7228e3e3a7aSWarner Losh return e->u.info; 7238e3e3a7aSWarner Losh } 7248e3e3a7aSWarner Losh } 7258e3e3a7aSWarner Losh luaK_exp2nextreg(fs, e); /* otherwise, use next available register */ 7268e3e3a7aSWarner Losh return e->u.info; 7278e3e3a7aSWarner Losh } 7288e3e3a7aSWarner Losh 7298e3e3a7aSWarner Losh 7308e3e3a7aSWarner Losh /* 7318e3e3a7aSWarner Losh ** Ensures final expression result is either in a register or in an 7328e3e3a7aSWarner Losh ** upvalue. 7338e3e3a7aSWarner Losh */ 7348e3e3a7aSWarner Losh void luaK_exp2anyregup (FuncState *fs, expdesc *e) { 7358e3e3a7aSWarner Losh if (e->k != VUPVAL || hasjumps(e)) 7368e3e3a7aSWarner Losh luaK_exp2anyreg(fs, e); 7378e3e3a7aSWarner Losh } 7388e3e3a7aSWarner Losh 7398e3e3a7aSWarner Losh 7408e3e3a7aSWarner Losh /* 7418e3e3a7aSWarner Losh ** Ensures final expression result is either in a register or it is 7428e3e3a7aSWarner Losh ** a constant. 7438e3e3a7aSWarner Losh */ 7448e3e3a7aSWarner Losh void luaK_exp2val (FuncState *fs, expdesc *e) { 7458e3e3a7aSWarner Losh if (hasjumps(e)) 7468e3e3a7aSWarner Losh luaK_exp2anyreg(fs, e); 7478e3e3a7aSWarner Losh else 7488e3e3a7aSWarner Losh luaK_dischargevars(fs, e); 7498e3e3a7aSWarner Losh } 7508e3e3a7aSWarner Losh 7518e3e3a7aSWarner Losh 7528e3e3a7aSWarner Losh /* 7538e3e3a7aSWarner Losh ** Ensures final expression result is in a valid R/K index 7548e3e3a7aSWarner Losh ** (that is, it is either in a register or in 'k' with an index 7558e3e3a7aSWarner Losh ** in the range of R/K indices). 7568e3e3a7aSWarner Losh ** Returns R/K index. 7578e3e3a7aSWarner Losh */ 7588e3e3a7aSWarner Losh int luaK_exp2RK (FuncState *fs, expdesc *e) { 7598e3e3a7aSWarner Losh luaK_exp2val(fs, e); 7608e3e3a7aSWarner Losh switch (e->k) { /* move constants to 'k' */ 7618e3e3a7aSWarner Losh case VTRUE: e->u.info = boolK(fs, 1); goto vk; 7628e3e3a7aSWarner Losh case VFALSE: e->u.info = boolK(fs, 0); goto vk; 7638e3e3a7aSWarner Losh case VNIL: e->u.info = nilK(fs); goto vk; 7648e3e3a7aSWarner Losh case VKINT: e->u.info = luaK_intK(fs, e->u.ival); goto vk; 7658e3e3a7aSWarner Losh case VKFLT: e->u.info = luaK_numberK(fs, e->u.nval); goto vk; 7668e3e3a7aSWarner Losh case VK: 7678e3e3a7aSWarner Losh vk: 7688e3e3a7aSWarner Losh e->k = VK; 7698e3e3a7aSWarner Losh if (e->u.info <= MAXINDEXRK) /* constant fits in 'argC'? */ 7708e3e3a7aSWarner Losh return RKASK(e->u.info); 7718e3e3a7aSWarner Losh else break; 7728e3e3a7aSWarner Losh default: break; 7738e3e3a7aSWarner Losh } 7748e3e3a7aSWarner Losh /* not a constant in the right range: put it in a register */ 7758e3e3a7aSWarner Losh return luaK_exp2anyreg(fs, e); 7768e3e3a7aSWarner Losh } 7778e3e3a7aSWarner Losh 7788e3e3a7aSWarner Losh 7798e3e3a7aSWarner Losh /* 7808e3e3a7aSWarner Losh ** Generate code to store result of expression 'ex' into variable 'var'. 7818e3e3a7aSWarner Losh */ 7828e3e3a7aSWarner Losh void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { 7838e3e3a7aSWarner Losh switch (var->k) { 7848e3e3a7aSWarner Losh case VLOCAL: { 7858e3e3a7aSWarner Losh freeexp(fs, ex); 7868e3e3a7aSWarner Losh exp2reg(fs, ex, var->u.info); /* compute 'ex' into proper place */ 7878e3e3a7aSWarner Losh return; 7888e3e3a7aSWarner Losh } 7898e3e3a7aSWarner Losh case VUPVAL: { 7908e3e3a7aSWarner Losh int e = luaK_exp2anyreg(fs, ex); 7918e3e3a7aSWarner Losh luaK_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0); 7928e3e3a7aSWarner Losh break; 7938e3e3a7aSWarner Losh } 7948e3e3a7aSWarner Losh case VINDEXED: { 7958e3e3a7aSWarner Losh OpCode op = (var->u.ind.vt == VLOCAL) ? OP_SETTABLE : OP_SETTABUP; 7968e3e3a7aSWarner Losh int e = luaK_exp2RK(fs, ex); 7978e3e3a7aSWarner Losh luaK_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e); 7988e3e3a7aSWarner Losh break; 7998e3e3a7aSWarner Losh } 8008e3e3a7aSWarner Losh default: lua_assert(0); /* invalid var kind to store */ 8018e3e3a7aSWarner Losh } 8028e3e3a7aSWarner Losh freeexp(fs, ex); 8038e3e3a7aSWarner Losh } 8048e3e3a7aSWarner Losh 8058e3e3a7aSWarner Losh 8068e3e3a7aSWarner Losh /* 8078e3e3a7aSWarner Losh ** Emit SELF instruction (convert expression 'e' into 'e:key(e,'). 8088e3e3a7aSWarner Losh */ 8098e3e3a7aSWarner Losh void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { 8108e3e3a7aSWarner Losh int ereg; 8118e3e3a7aSWarner Losh luaK_exp2anyreg(fs, e); 8128e3e3a7aSWarner Losh ereg = e->u.info; /* register where 'e' was placed */ 8138e3e3a7aSWarner Losh freeexp(fs, e); 8148e3e3a7aSWarner Losh e->u.info = fs->freereg; /* base register for op_self */ 8158e3e3a7aSWarner Losh e->k = VNONRELOC; /* self expression has a fixed register */ 8168e3e3a7aSWarner Losh luaK_reserveregs(fs, 2); /* function and 'self' produced by op_self */ 8178e3e3a7aSWarner Losh luaK_codeABC(fs, OP_SELF, e->u.info, ereg, luaK_exp2RK(fs, key)); 8188e3e3a7aSWarner Losh freeexp(fs, key); 8198e3e3a7aSWarner Losh } 8208e3e3a7aSWarner Losh 8218e3e3a7aSWarner Losh 8228e3e3a7aSWarner Losh /* 8238e3e3a7aSWarner Losh ** Negate condition 'e' (where 'e' is a comparison). 8248e3e3a7aSWarner Losh */ 8258e3e3a7aSWarner Losh static void negatecondition (FuncState *fs, expdesc *e) { 8268e3e3a7aSWarner Losh Instruction *pc = getjumpcontrol(fs, e->u.info); 8278e3e3a7aSWarner Losh lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET && 8288e3e3a7aSWarner Losh GET_OPCODE(*pc) != OP_TEST); 8298e3e3a7aSWarner Losh SETARG_A(*pc, !(GETARG_A(*pc))); 8308e3e3a7aSWarner Losh } 8318e3e3a7aSWarner Losh 8328e3e3a7aSWarner Losh 8338e3e3a7aSWarner Losh /* 8348e3e3a7aSWarner Losh ** Emit instruction to jump if 'e' is 'cond' (that is, if 'cond' 8358e3e3a7aSWarner Losh ** is true, code will jump if 'e' is true.) Return jump position. 8368e3e3a7aSWarner Losh ** Optimize when 'e' is 'not' something, inverting the condition 8378e3e3a7aSWarner Losh ** and removing the 'not'. 8388e3e3a7aSWarner Losh */ 8398e3e3a7aSWarner Losh static int jumponcond (FuncState *fs, expdesc *e, int cond) { 8408e3e3a7aSWarner Losh if (e->k == VRELOCABLE) { 8418e3e3a7aSWarner Losh Instruction ie = getinstruction(fs, e); 8428e3e3a7aSWarner Losh if (GET_OPCODE(ie) == OP_NOT) { 8438e3e3a7aSWarner Losh fs->pc--; /* remove previous OP_NOT */ 8448e3e3a7aSWarner Losh return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond); 8458e3e3a7aSWarner Losh } 8468e3e3a7aSWarner Losh /* else go through */ 8478e3e3a7aSWarner Losh } 8488e3e3a7aSWarner Losh discharge2anyreg(fs, e); 8498e3e3a7aSWarner Losh freeexp(fs, e); 8508e3e3a7aSWarner Losh return condjump(fs, OP_TESTSET, NO_REG, e->u.info, cond); 8518e3e3a7aSWarner Losh } 8528e3e3a7aSWarner Losh 8538e3e3a7aSWarner Losh 8548e3e3a7aSWarner Losh /* 8558e3e3a7aSWarner Losh ** Emit code to go through if 'e' is true, jump otherwise. 8568e3e3a7aSWarner Losh */ 8578e3e3a7aSWarner Losh void luaK_goiftrue (FuncState *fs, expdesc *e) { 8588e3e3a7aSWarner Losh int pc; /* pc of new jump */ 8598e3e3a7aSWarner Losh luaK_dischargevars(fs, e); 8608e3e3a7aSWarner Losh switch (e->k) { 8618e3e3a7aSWarner Losh case VJMP: { /* condition? */ 8628e3e3a7aSWarner Losh negatecondition(fs, e); /* jump when it is false */ 8638e3e3a7aSWarner Losh pc = e->u.info; /* save jump position */ 8648e3e3a7aSWarner Losh break; 8658e3e3a7aSWarner Losh } 8668e3e3a7aSWarner Losh case VK: case VKFLT: case VKINT: case VTRUE: { 8678e3e3a7aSWarner Losh pc = NO_JUMP; /* always true; do nothing */ 8688e3e3a7aSWarner Losh break; 8698e3e3a7aSWarner Losh } 8708e3e3a7aSWarner Losh default: { 8718e3e3a7aSWarner Losh pc = jumponcond(fs, e, 0); /* jump when false */ 8728e3e3a7aSWarner Losh break; 8738e3e3a7aSWarner Losh } 8748e3e3a7aSWarner Losh } 8758e3e3a7aSWarner Losh luaK_concat(fs, &e->f, pc); /* insert new jump in false list */ 8768e3e3a7aSWarner Losh luaK_patchtohere(fs, e->t); /* true list jumps to here (to go through) */ 8778e3e3a7aSWarner Losh e->t = NO_JUMP; 8788e3e3a7aSWarner Losh } 8798e3e3a7aSWarner Losh 8808e3e3a7aSWarner Losh 8818e3e3a7aSWarner Losh /* 8828e3e3a7aSWarner Losh ** Emit code to go through if 'e' is false, jump otherwise. 8838e3e3a7aSWarner Losh */ 8848e3e3a7aSWarner Losh void luaK_goiffalse (FuncState *fs, expdesc *e) { 8858e3e3a7aSWarner Losh int pc; /* pc of new jump */ 8868e3e3a7aSWarner Losh luaK_dischargevars(fs, e); 8878e3e3a7aSWarner Losh switch (e->k) { 8888e3e3a7aSWarner Losh case VJMP: { 8898e3e3a7aSWarner Losh pc = e->u.info; /* already jump if true */ 8908e3e3a7aSWarner Losh break; 8918e3e3a7aSWarner Losh } 8928e3e3a7aSWarner Losh case VNIL: case VFALSE: { 8938e3e3a7aSWarner Losh pc = NO_JUMP; /* always false; do nothing */ 8948e3e3a7aSWarner Losh break; 8958e3e3a7aSWarner Losh } 8968e3e3a7aSWarner Losh default: { 8978e3e3a7aSWarner Losh pc = jumponcond(fs, e, 1); /* jump if true */ 8988e3e3a7aSWarner Losh break; 8998e3e3a7aSWarner Losh } 9008e3e3a7aSWarner Losh } 9018e3e3a7aSWarner Losh luaK_concat(fs, &e->t, pc); /* insert new jump in 't' list */ 9028e3e3a7aSWarner Losh luaK_patchtohere(fs, e->f); /* false list jumps to here (to go through) */ 9038e3e3a7aSWarner Losh e->f = NO_JUMP; 9048e3e3a7aSWarner Losh } 9058e3e3a7aSWarner Losh 9068e3e3a7aSWarner Losh 9078e3e3a7aSWarner Losh /* 9088e3e3a7aSWarner Losh ** Code 'not e', doing constant folding. 9098e3e3a7aSWarner Losh */ 9108e3e3a7aSWarner Losh static void codenot (FuncState *fs, expdesc *e) { 9118e3e3a7aSWarner Losh luaK_dischargevars(fs, e); 9128e3e3a7aSWarner Losh switch (e->k) { 9138e3e3a7aSWarner Losh case VNIL: case VFALSE: { 9148e3e3a7aSWarner Losh e->k = VTRUE; /* true == not nil == not false */ 9158e3e3a7aSWarner Losh break; 9168e3e3a7aSWarner Losh } 9178e3e3a7aSWarner Losh case VK: case VKFLT: case VKINT: case VTRUE: { 9188e3e3a7aSWarner Losh e->k = VFALSE; /* false == not "x" == not 0.5 == not 1 == not true */ 9198e3e3a7aSWarner Losh break; 9208e3e3a7aSWarner Losh } 9218e3e3a7aSWarner Losh case VJMP: { 9228e3e3a7aSWarner Losh negatecondition(fs, e); 9238e3e3a7aSWarner Losh break; 9248e3e3a7aSWarner Losh } 9258e3e3a7aSWarner Losh case VRELOCABLE: 9268e3e3a7aSWarner Losh case VNONRELOC: { 9278e3e3a7aSWarner Losh discharge2anyreg(fs, e); 9288e3e3a7aSWarner Losh freeexp(fs, e); 9298e3e3a7aSWarner Losh e->u.info = luaK_codeABC(fs, OP_NOT, 0, e->u.info, 0); 9308e3e3a7aSWarner Losh e->k = VRELOCABLE; 9318e3e3a7aSWarner Losh break; 9328e3e3a7aSWarner Losh } 9338e3e3a7aSWarner Losh default: lua_assert(0); /* cannot happen */ 9348e3e3a7aSWarner Losh } 9358e3e3a7aSWarner Losh /* interchange true and false lists */ 9368e3e3a7aSWarner Losh { int temp = e->f; e->f = e->t; e->t = temp; } 9378e3e3a7aSWarner Losh removevalues(fs, e->f); /* values are useless when negated */ 9388e3e3a7aSWarner Losh removevalues(fs, e->t); 9398e3e3a7aSWarner Losh } 9408e3e3a7aSWarner Losh 9418e3e3a7aSWarner Losh 9428e3e3a7aSWarner Losh /* 9438e3e3a7aSWarner Losh ** Create expression 't[k]'. 't' must have its final result already in a 9448e3e3a7aSWarner Losh ** register or upvalue. 9458e3e3a7aSWarner Losh */ 9468e3e3a7aSWarner Losh void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { 9478e3e3a7aSWarner Losh lua_assert(!hasjumps(t) && (vkisinreg(t->k) || t->k == VUPVAL)); 9488e3e3a7aSWarner Losh t->u.ind.t = t->u.info; /* register or upvalue index */ 9498e3e3a7aSWarner Losh t->u.ind.idx = luaK_exp2RK(fs, k); /* R/K index for key */ 9508e3e3a7aSWarner Losh t->u.ind.vt = (t->k == VUPVAL) ? VUPVAL : VLOCAL; 9518e3e3a7aSWarner Losh t->k = VINDEXED; 9528e3e3a7aSWarner Losh } 9538e3e3a7aSWarner Losh 9548e3e3a7aSWarner Losh 9558e3e3a7aSWarner Losh /* 9568e3e3a7aSWarner Losh ** Return false if folding can raise an error. 9578e3e3a7aSWarner Losh ** Bitwise operations need operands convertible to integers; division 9588e3e3a7aSWarner Losh ** operations cannot have 0 as divisor. 9598e3e3a7aSWarner Losh */ 9608e3e3a7aSWarner Losh static int validop (int op, TValue *v1, TValue *v2) { 9618e3e3a7aSWarner Losh switch (op) { 9628e3e3a7aSWarner Losh case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR: 9638e3e3a7aSWarner Losh case LUA_OPSHL: case LUA_OPSHR: case LUA_OPBNOT: { /* conversion errors */ 9648e3e3a7aSWarner Losh lua_Integer i; 9658e3e3a7aSWarner Losh return (tointeger(v1, &i) && tointeger(v2, &i)); 9668e3e3a7aSWarner Losh } 9678e3e3a7aSWarner Losh case LUA_OPDIV: case LUA_OPIDIV: case LUA_OPMOD: /* division by 0 */ 9688e3e3a7aSWarner Losh return (nvalue(v2) != 0); 9698e3e3a7aSWarner Losh default: return 1; /* everything else is valid */ 9708e3e3a7aSWarner Losh } 9718e3e3a7aSWarner Losh } 9728e3e3a7aSWarner Losh 9738e3e3a7aSWarner Losh 9748e3e3a7aSWarner Losh /* 9758e3e3a7aSWarner Losh ** Try to "constant-fold" an operation; return 1 iff successful. 9768e3e3a7aSWarner Losh ** (In this case, 'e1' has the final result.) 9778e3e3a7aSWarner Losh */ 9788e3e3a7aSWarner Losh static int constfolding (FuncState *fs, int op, expdesc *e1, 9798e3e3a7aSWarner Losh const expdesc *e2) { 9808e3e3a7aSWarner Losh TValue v1, v2, res; 9818e3e3a7aSWarner Losh if (!tonumeral(e1, &v1) || !tonumeral(e2, &v2) || !validop(op, &v1, &v2)) 9828e3e3a7aSWarner Losh return 0; /* non-numeric operands or not safe to fold */ 9838e3e3a7aSWarner Losh luaO_arith(fs->ls->L, op, &v1, &v2, &res); /* does operation */ 9848e3e3a7aSWarner Losh if (ttisinteger(&res)) { 9858e3e3a7aSWarner Losh e1->k = VKINT; 9868e3e3a7aSWarner Losh e1->u.ival = ivalue(&res); 9878e3e3a7aSWarner Losh } 9888e3e3a7aSWarner Losh else { /* folds neither NaN nor 0.0 (to avoid problems with -0.0) */ 9898e3e3a7aSWarner Losh lua_Number n = fltvalue(&res); 9908e3e3a7aSWarner Losh if (luai_numisnan(n) || n == 0) 9918e3e3a7aSWarner Losh return 0; 9928e3e3a7aSWarner Losh e1->k = VKFLT; 9938e3e3a7aSWarner Losh e1->u.nval = n; 9948e3e3a7aSWarner Losh } 9958e3e3a7aSWarner Losh return 1; 9968e3e3a7aSWarner Losh } 9978e3e3a7aSWarner Losh 9988e3e3a7aSWarner Losh 9998e3e3a7aSWarner Losh /* 10008e3e3a7aSWarner Losh ** Emit code for unary expressions that "produce values" 10018e3e3a7aSWarner Losh ** (everything but 'not'). 10028e3e3a7aSWarner Losh ** Expression to produce final result will be encoded in 'e'. 10038e3e3a7aSWarner Losh */ 10048e3e3a7aSWarner Losh static void codeunexpval (FuncState *fs, OpCode op, expdesc *e, int line) { 10058e3e3a7aSWarner Losh int r = luaK_exp2anyreg(fs, e); /* opcodes operate only on registers */ 10068e3e3a7aSWarner Losh freeexp(fs, e); 10078e3e3a7aSWarner Losh e->u.info = luaK_codeABC(fs, op, 0, r, 0); /* generate opcode */ 10088e3e3a7aSWarner Losh e->k = VRELOCABLE; /* all those operations are relocatable */ 10098e3e3a7aSWarner Losh luaK_fixline(fs, line); 10108e3e3a7aSWarner Losh } 10118e3e3a7aSWarner Losh 10128e3e3a7aSWarner Losh 10138e3e3a7aSWarner Losh /* 10148e3e3a7aSWarner Losh ** Emit code for binary expressions that "produce values" 10158e3e3a7aSWarner Losh ** (everything but logical operators 'and'/'or' and comparison 10168e3e3a7aSWarner Losh ** operators). 10178e3e3a7aSWarner Losh ** Expression to produce final result will be encoded in 'e1'. 10188e3e3a7aSWarner Losh ** Because 'luaK_exp2RK' can free registers, its calls must be 10198e3e3a7aSWarner Losh ** in "stack order" (that is, first on 'e2', which may have more 10208e3e3a7aSWarner Losh ** recent registers to be released). 10218e3e3a7aSWarner Losh */ 10228e3e3a7aSWarner Losh static void codebinexpval (FuncState *fs, OpCode op, 10238e3e3a7aSWarner Losh expdesc *e1, expdesc *e2, int line) { 10248e3e3a7aSWarner Losh int rk2 = luaK_exp2RK(fs, e2); /* both operands are "RK" */ 10258e3e3a7aSWarner Losh int rk1 = luaK_exp2RK(fs, e1); 10268e3e3a7aSWarner Losh freeexps(fs, e1, e2); 10278e3e3a7aSWarner Losh e1->u.info = luaK_codeABC(fs, op, 0, rk1, rk2); /* generate opcode */ 10288e3e3a7aSWarner Losh e1->k = VRELOCABLE; /* all those operations are relocatable */ 10298e3e3a7aSWarner Losh luaK_fixline(fs, line); 10308e3e3a7aSWarner Losh } 10318e3e3a7aSWarner Losh 10328e3e3a7aSWarner Losh 10338e3e3a7aSWarner Losh /* 10348e3e3a7aSWarner Losh ** Emit code for comparisons. 10358e3e3a7aSWarner Losh ** 'e1' was already put in R/K form by 'luaK_infix'. 10368e3e3a7aSWarner Losh */ 10378e3e3a7aSWarner Losh static void codecomp (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) { 10388e3e3a7aSWarner Losh int rk1 = (e1->k == VK) ? RKASK(e1->u.info) 10398e3e3a7aSWarner Losh : check_exp(e1->k == VNONRELOC, e1->u.info); 10408e3e3a7aSWarner Losh int rk2 = luaK_exp2RK(fs, e2); 10418e3e3a7aSWarner Losh freeexps(fs, e1, e2); 10428e3e3a7aSWarner Losh switch (opr) { 10438e3e3a7aSWarner Losh case OPR_NE: { /* '(a ~= b)' ==> 'not (a == b)' */ 10448e3e3a7aSWarner Losh e1->u.info = condjump(fs, OP_EQ, 0, rk1, rk2); 10458e3e3a7aSWarner Losh break; 10468e3e3a7aSWarner Losh } 10478e3e3a7aSWarner Losh case OPR_GT: case OPR_GE: { 10488e3e3a7aSWarner Losh /* '(a > b)' ==> '(b < a)'; '(a >= b)' ==> '(b <= a)' */ 10498e3e3a7aSWarner Losh OpCode op = cast(OpCode, (opr - OPR_NE) + OP_EQ); 10508e3e3a7aSWarner Losh e1->u.info = condjump(fs, op, 1, rk2, rk1); /* invert operands */ 10518e3e3a7aSWarner Losh break; 10528e3e3a7aSWarner Losh } 10538e3e3a7aSWarner Losh default: { /* '==', '<', '<=' use their own opcodes */ 10548e3e3a7aSWarner Losh OpCode op = cast(OpCode, (opr - OPR_EQ) + OP_EQ); 10558e3e3a7aSWarner Losh e1->u.info = condjump(fs, op, 1, rk1, rk2); 10568e3e3a7aSWarner Losh break; 10578e3e3a7aSWarner Losh } 10588e3e3a7aSWarner Losh } 10598e3e3a7aSWarner Losh e1->k = VJMP; 10608e3e3a7aSWarner Losh } 10618e3e3a7aSWarner Losh 10628e3e3a7aSWarner Losh 10638e3e3a7aSWarner Losh /* 1064*bf9580a1SKyle Evans ** Apply prefix operation 'op' to expression 'e'. 10658e3e3a7aSWarner Losh */ 10668e3e3a7aSWarner Losh void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) { 10678e3e3a7aSWarner Losh static const expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP}; 10688e3e3a7aSWarner Losh switch (op) { 10698e3e3a7aSWarner Losh case OPR_MINUS: case OPR_BNOT: /* use 'ef' as fake 2nd operand */ 10708e3e3a7aSWarner Losh if (constfolding(fs, op + LUA_OPUNM, e, &ef)) 10718e3e3a7aSWarner Losh break; 10728e3e3a7aSWarner Losh /* FALLTHROUGH */ 10738e3e3a7aSWarner Losh case OPR_LEN: 10748e3e3a7aSWarner Losh codeunexpval(fs, cast(OpCode, op + OP_UNM), e, line); 10758e3e3a7aSWarner Losh break; 10768e3e3a7aSWarner Losh case OPR_NOT: codenot(fs, e); break; 10778e3e3a7aSWarner Losh default: lua_assert(0); 10788e3e3a7aSWarner Losh } 10798e3e3a7aSWarner Losh } 10808e3e3a7aSWarner Losh 10818e3e3a7aSWarner Losh 10828e3e3a7aSWarner Losh /* 10838e3e3a7aSWarner Losh ** Process 1st operand 'v' of binary operation 'op' before reading 10848e3e3a7aSWarner Losh ** 2nd operand. 10858e3e3a7aSWarner Losh */ 10868e3e3a7aSWarner Losh void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { 10878e3e3a7aSWarner Losh switch (op) { 10888e3e3a7aSWarner Losh case OPR_AND: { 10898e3e3a7aSWarner Losh luaK_goiftrue(fs, v); /* go ahead only if 'v' is true */ 10908e3e3a7aSWarner Losh break; 10918e3e3a7aSWarner Losh } 10928e3e3a7aSWarner Losh case OPR_OR: { 10938e3e3a7aSWarner Losh luaK_goiffalse(fs, v); /* go ahead only if 'v' is false */ 10948e3e3a7aSWarner Losh break; 10958e3e3a7aSWarner Losh } 10968e3e3a7aSWarner Losh case OPR_CONCAT: { 10978e3e3a7aSWarner Losh luaK_exp2nextreg(fs, v); /* operand must be on the 'stack' */ 10988e3e3a7aSWarner Losh break; 10998e3e3a7aSWarner Losh } 11008e3e3a7aSWarner Losh case OPR_ADD: case OPR_SUB: 11018e3e3a7aSWarner Losh case OPR_MUL: case OPR_DIV: case OPR_IDIV: 11028e3e3a7aSWarner Losh case OPR_MOD: case OPR_POW: 11038e3e3a7aSWarner Losh case OPR_BAND: case OPR_BOR: case OPR_BXOR: 11048e3e3a7aSWarner Losh case OPR_SHL: case OPR_SHR: { 11058e3e3a7aSWarner Losh if (!tonumeral(v, NULL)) 11068e3e3a7aSWarner Losh luaK_exp2RK(fs, v); 11078e3e3a7aSWarner Losh /* else keep numeral, which may be folded with 2nd operand */ 11088e3e3a7aSWarner Losh break; 11098e3e3a7aSWarner Losh } 11108e3e3a7aSWarner Losh default: { 11118e3e3a7aSWarner Losh luaK_exp2RK(fs, v); 11128e3e3a7aSWarner Losh break; 11138e3e3a7aSWarner Losh } 11148e3e3a7aSWarner Losh } 11158e3e3a7aSWarner Losh } 11168e3e3a7aSWarner Losh 11178e3e3a7aSWarner Losh 11188e3e3a7aSWarner Losh /* 11198e3e3a7aSWarner Losh ** Finalize code for binary operation, after reading 2nd operand. 11208e3e3a7aSWarner Losh ** For '(a .. b .. c)' (which is '(a .. (b .. c))', because 11218e3e3a7aSWarner Losh ** concatenation is right associative), merge second CONCAT into first 11228e3e3a7aSWarner Losh ** one. 11238e3e3a7aSWarner Losh */ 11248e3e3a7aSWarner Losh void luaK_posfix (FuncState *fs, BinOpr op, 11258e3e3a7aSWarner Losh expdesc *e1, expdesc *e2, int line) { 11268e3e3a7aSWarner Losh switch (op) { 11278e3e3a7aSWarner Losh case OPR_AND: { 11288e3e3a7aSWarner Losh lua_assert(e1->t == NO_JUMP); /* list closed by 'luK_infix' */ 11298e3e3a7aSWarner Losh luaK_dischargevars(fs, e2); 11308e3e3a7aSWarner Losh luaK_concat(fs, &e2->f, e1->f); 11318e3e3a7aSWarner Losh *e1 = *e2; 11328e3e3a7aSWarner Losh break; 11338e3e3a7aSWarner Losh } 11348e3e3a7aSWarner Losh case OPR_OR: { 11358e3e3a7aSWarner Losh lua_assert(e1->f == NO_JUMP); /* list closed by 'luK_infix' */ 11368e3e3a7aSWarner Losh luaK_dischargevars(fs, e2); 11378e3e3a7aSWarner Losh luaK_concat(fs, &e2->t, e1->t); 11388e3e3a7aSWarner Losh *e1 = *e2; 11398e3e3a7aSWarner Losh break; 11408e3e3a7aSWarner Losh } 11418e3e3a7aSWarner Losh case OPR_CONCAT: { 11428e3e3a7aSWarner Losh luaK_exp2val(fs, e2); 11438e3e3a7aSWarner Losh if (e2->k == VRELOCABLE && 11448e3e3a7aSWarner Losh GET_OPCODE(getinstruction(fs, e2)) == OP_CONCAT) { 11458e3e3a7aSWarner Losh lua_assert(e1->u.info == GETARG_B(getinstruction(fs, e2))-1); 11468e3e3a7aSWarner Losh freeexp(fs, e1); 11478e3e3a7aSWarner Losh SETARG_B(getinstruction(fs, e2), e1->u.info); 11488e3e3a7aSWarner Losh e1->k = VRELOCABLE; e1->u.info = e2->u.info; 11498e3e3a7aSWarner Losh } 11508e3e3a7aSWarner Losh else { 11518e3e3a7aSWarner Losh luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */ 11528e3e3a7aSWarner Losh codebinexpval(fs, OP_CONCAT, e1, e2, line); 11538e3e3a7aSWarner Losh } 11548e3e3a7aSWarner Losh break; 11558e3e3a7aSWarner Losh } 11568e3e3a7aSWarner Losh case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: 11578e3e3a7aSWarner Losh case OPR_IDIV: case OPR_MOD: case OPR_POW: 11588e3e3a7aSWarner Losh case OPR_BAND: case OPR_BOR: case OPR_BXOR: 11598e3e3a7aSWarner Losh case OPR_SHL: case OPR_SHR: { 11608e3e3a7aSWarner Losh if (!constfolding(fs, op + LUA_OPADD, e1, e2)) 11618e3e3a7aSWarner Losh codebinexpval(fs, cast(OpCode, op + OP_ADD), e1, e2, line); 11628e3e3a7aSWarner Losh break; 11638e3e3a7aSWarner Losh } 11648e3e3a7aSWarner Losh case OPR_EQ: case OPR_LT: case OPR_LE: 11658e3e3a7aSWarner Losh case OPR_NE: case OPR_GT: case OPR_GE: { 11668e3e3a7aSWarner Losh codecomp(fs, op, e1, e2); 11678e3e3a7aSWarner Losh break; 11688e3e3a7aSWarner Losh } 11698e3e3a7aSWarner Losh default: lua_assert(0); 11708e3e3a7aSWarner Losh } 11718e3e3a7aSWarner Losh } 11728e3e3a7aSWarner Losh 11738e3e3a7aSWarner Losh 11748e3e3a7aSWarner Losh /* 11758e3e3a7aSWarner Losh ** Change line information associated with current position. 11768e3e3a7aSWarner Losh */ 11778e3e3a7aSWarner Losh void luaK_fixline (FuncState *fs, int line) { 11788e3e3a7aSWarner Losh fs->f->lineinfo[fs->pc - 1] = line; 11798e3e3a7aSWarner Losh } 11808e3e3a7aSWarner Losh 11818e3e3a7aSWarner Losh 11828e3e3a7aSWarner Losh /* 11838e3e3a7aSWarner Losh ** Emit a SETLIST instruction. 11848e3e3a7aSWarner Losh ** 'base' is register that keeps table; 11858e3e3a7aSWarner Losh ** 'nelems' is #table plus those to be stored now; 11868e3e3a7aSWarner Losh ** 'tostore' is number of values (in registers 'base + 1',...) to add to 11878e3e3a7aSWarner Losh ** table (or LUA_MULTRET to add up to stack top). 11888e3e3a7aSWarner Losh */ 11898e3e3a7aSWarner Losh void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) { 11908e3e3a7aSWarner Losh int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1; 11918e3e3a7aSWarner Losh int b = (tostore == LUA_MULTRET) ? 0 : tostore; 11928e3e3a7aSWarner Losh lua_assert(tostore != 0 && tostore <= LFIELDS_PER_FLUSH); 11938e3e3a7aSWarner Losh if (c <= MAXARG_C) 11948e3e3a7aSWarner Losh luaK_codeABC(fs, OP_SETLIST, base, b, c); 11958e3e3a7aSWarner Losh else if (c <= MAXARG_Ax) { 11968e3e3a7aSWarner Losh luaK_codeABC(fs, OP_SETLIST, base, b, 0); 11978e3e3a7aSWarner Losh codeextraarg(fs, c); 11988e3e3a7aSWarner Losh } 11998e3e3a7aSWarner Losh else 12008e3e3a7aSWarner Losh luaX_syntaxerror(fs->ls, "constructor too long"); 12018e3e3a7aSWarner Losh fs->freereg = base + 1; /* free registers with list values */ 12028e3e3a7aSWarner Losh } 12038e3e3a7aSWarner Losh 1204