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