diff src/lua/src/lcode.c @ 1:f9f4f1b99eed

importing src directory
author Robert McIntyre <rlm@mit.edu>
date Sat, 03 Mar 2012 10:31:27 -0600
parents
children
line wrap: on
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/lua/src/lcode.c	Sat Mar 03 10:31:27 2012 -0600
     1.3 @@ -0,0 +1,839 @@
     1.4 +/*
     1.5 +** $Id: lcode.c,v 2.25.1.3 2007/12/28 15:32:23 roberto Exp $
     1.6 +** Code generator for Lua
     1.7 +** See Copyright Notice in lua.h
     1.8 +*/
     1.9 +
    1.10 +
    1.11 +#include <stdlib.h>
    1.12 +
    1.13 +#define lcode_c
    1.14 +#define LUA_CORE
    1.15 +
    1.16 +#include "lua.h"
    1.17 +
    1.18 +#include "lcode.h"
    1.19 +#include "ldebug.h"
    1.20 +#include "ldo.h"
    1.21 +#include "lgc.h"
    1.22 +#include "llex.h"
    1.23 +#include "lmem.h"
    1.24 +#include "lobject.h"
    1.25 +#include "lopcodes.h"
    1.26 +#include "lparser.h"
    1.27 +#include "ltable.h"
    1.28 +
    1.29 +
    1.30 +#define hasjumps(e)	((e)->t != (e)->f)
    1.31 +
    1.32 +
    1.33 +static int isnumeral(expdesc *e) {
    1.34 +  return (e->k == VKNUM && e->t == NO_JUMP && e->f == NO_JUMP);
    1.35 +}
    1.36 +
    1.37 +
    1.38 +void luaK_nil (FuncState *fs, int from, int n) {
    1.39 +  Instruction *previous;
    1.40 +  if (fs->pc > fs->lasttarget) {  /* no jumps to current position? */
    1.41 +    if (fs->pc == 0) {  /* function start? */
    1.42 +      if (from >= fs->nactvar)
    1.43 +        return;  /* positions are already clean */
    1.44 +    }
    1.45 +    else {
    1.46 +      previous = &fs->f->code[fs->pc-1];
    1.47 +      if (GET_OPCODE(*previous) == OP_LOADNIL) {
    1.48 +        int pfrom = GETARG_A(*previous);
    1.49 +        int pto = GETARG_B(*previous);
    1.50 +        if (pfrom <= from && from <= pto+1) {  /* can connect both? */
    1.51 +          if (from+n-1 > pto)
    1.52 +            SETARG_B(*previous, from+n-1);
    1.53 +          return;
    1.54 +        }
    1.55 +      }
    1.56 +    }
    1.57 +  }
    1.58 +  luaK_codeABC(fs, OP_LOADNIL, from, from+n-1, 0);  /* else no optimization */
    1.59 +}
    1.60 +
    1.61 +
    1.62 +int luaK_jump (FuncState *fs) {
    1.63 +  int jpc = fs->jpc;  /* save list of jumps to here */
    1.64 +  int j;
    1.65 +  fs->jpc = NO_JUMP;
    1.66 +  j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP);
    1.67 +  luaK_concat(fs, &j, jpc);  /* keep them on hold */
    1.68 +  return j;
    1.69 +}
    1.70 +
    1.71 +
    1.72 +void luaK_ret (FuncState *fs, int first, int nret) {
    1.73 +  luaK_codeABC(fs, OP_RETURN, first, nret+1, 0);
    1.74 +}
    1.75 +
    1.76 +
    1.77 +static int condjump (FuncState *fs, OpCode op, int A, int B, int C) {
    1.78 +  luaK_codeABC(fs, op, A, B, C);
    1.79 +  return luaK_jump(fs);
    1.80 +}
    1.81 +
    1.82 +
    1.83 +static void fixjump (FuncState *fs, int pc, int dest) {
    1.84 +  Instruction *jmp = &fs->f->code[pc];
    1.85 +  int offset = dest-(pc+1);
    1.86 +  lua_assert(dest != NO_JUMP);
    1.87 +  if (abs(offset) > MAXARG_sBx)
    1.88 +    luaX_syntaxerror(fs->ls, "control structure too long");
    1.89 +  SETARG_sBx(*jmp, offset);
    1.90 +}
    1.91 +
    1.92 +
    1.93 +/*
    1.94 +** returns current `pc' and marks it as a jump target (to avoid wrong
    1.95 +** optimizations with consecutive instructions not in the same basic block).
    1.96 +*/
    1.97 +int luaK_getlabel (FuncState *fs) {
    1.98 +  fs->lasttarget = fs->pc;
    1.99 +  return fs->pc;
   1.100 +}
   1.101 +
   1.102 +
   1.103 +static int getjump (FuncState *fs, int pc) {
   1.104 +  int offset = GETARG_sBx(fs->f->code[pc]);
   1.105 +  if (offset == NO_JUMP)  /* point to itself represents end of list */
   1.106 +    return NO_JUMP;  /* end of list */
   1.107 +  else
   1.108 +    return (pc+1)+offset;  /* turn offset into absolute position */
   1.109 +}
   1.110 +
   1.111 +
   1.112 +static Instruction *getjumpcontrol (FuncState *fs, int pc) {
   1.113 +  Instruction *pi = &fs->f->code[pc];
   1.114 +  if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1))))
   1.115 +    return pi-1;
   1.116 +  else
   1.117 +    return pi;
   1.118 +}
   1.119 +
   1.120 +
   1.121 +/*
   1.122 +** check whether list has any jump that do not produce a value
   1.123 +** (or produce an inverted value)
   1.124 +*/
   1.125 +static int need_value (FuncState *fs, int list) {
   1.126 +  for (; list != NO_JUMP; list = getjump(fs, list)) {
   1.127 +    Instruction i = *getjumpcontrol(fs, list);
   1.128 +    if (GET_OPCODE(i) != OP_TESTSET) return 1;
   1.129 +  }
   1.130 +  return 0;  /* not found */
   1.131 +}
   1.132 +
   1.133 +
   1.134 +static int patchtestreg (FuncState *fs, int node, int reg) {
   1.135 +  Instruction *i = getjumpcontrol(fs, node);
   1.136 +  if (GET_OPCODE(*i) != OP_TESTSET)
   1.137 +    return 0;  /* cannot patch other instructions */
   1.138 +  if (reg != NO_REG && reg != GETARG_B(*i))
   1.139 +    SETARG_A(*i, reg);
   1.140 +  else  /* no register to put value or register already has the value */
   1.141 +    *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i));
   1.142 +
   1.143 +  return 1;
   1.144 +}
   1.145 +
   1.146 +
   1.147 +static void removevalues (FuncState *fs, int list) {
   1.148 +  for (; list != NO_JUMP; list = getjump(fs, list))
   1.149 +      patchtestreg(fs, list, NO_REG);
   1.150 +}
   1.151 +
   1.152 +
   1.153 +static void patchlistaux (FuncState *fs, int list, int vtarget, int reg,
   1.154 +                          int dtarget) {
   1.155 +  while (list != NO_JUMP) {
   1.156 +    int next = getjump(fs, list);
   1.157 +    if (patchtestreg(fs, list, reg))
   1.158 +      fixjump(fs, list, vtarget);
   1.159 +    else
   1.160 +      fixjump(fs, list, dtarget);  /* jump to default target */
   1.161 +    list = next;
   1.162 +  }
   1.163 +}
   1.164 +
   1.165 +
   1.166 +static void dischargejpc (FuncState *fs) {
   1.167 +  patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc);
   1.168 +  fs->jpc = NO_JUMP;
   1.169 +}
   1.170 +
   1.171 +
   1.172 +void luaK_patchlist (FuncState *fs, int list, int target) {
   1.173 +  if (target == fs->pc)
   1.174 +    luaK_patchtohere(fs, list);
   1.175 +  else {
   1.176 +    lua_assert(target < fs->pc);
   1.177 +    patchlistaux(fs, list, target, NO_REG, target);
   1.178 +  }
   1.179 +}
   1.180 +
   1.181 +
   1.182 +void luaK_patchtohere (FuncState *fs, int list) {
   1.183 +  luaK_getlabel(fs);
   1.184 +  luaK_concat(fs, &fs->jpc, list);
   1.185 +}
   1.186 +
   1.187 +
   1.188 +void luaK_concat (FuncState *fs, int *l1, int l2) {
   1.189 +  if (l2 == NO_JUMP) return;
   1.190 +  else if (*l1 == NO_JUMP)
   1.191 +    *l1 = l2;
   1.192 +  else {
   1.193 +    int list = *l1;
   1.194 +    int next;
   1.195 +    while ((next = getjump(fs, list)) != NO_JUMP)  /* find last element */
   1.196 +      list = next;
   1.197 +    fixjump(fs, list, l2);
   1.198 +  }
   1.199 +}
   1.200 +
   1.201 +
   1.202 +void luaK_checkstack (FuncState *fs, int n) {
   1.203 +  int newstack = fs->freereg + n;
   1.204 +  if (newstack > fs->f->maxstacksize) {
   1.205 +    if (newstack >= MAXSTACK)
   1.206 +      luaX_syntaxerror(fs->ls, "function or expression too complex");
   1.207 +    fs->f->maxstacksize = cast_byte(newstack);
   1.208 +  }
   1.209 +}
   1.210 +
   1.211 +
   1.212 +void luaK_reserveregs (FuncState *fs, int n) {
   1.213 +  luaK_checkstack(fs, n);
   1.214 +  fs->freereg += n;
   1.215 +}
   1.216 +
   1.217 +
   1.218 +static void freereg (FuncState *fs, int reg) {
   1.219 +  if (!ISK(reg) && reg >= fs->nactvar) {
   1.220 +    fs->freereg--;
   1.221 +    lua_assert(reg == fs->freereg);
   1.222 +  }
   1.223 +}
   1.224 +
   1.225 +
   1.226 +static void freeexp (FuncState *fs, expdesc *e) {
   1.227 +  if (e->k == VNONRELOC)
   1.228 +    freereg(fs, e->u.s.info);
   1.229 +}
   1.230 +
   1.231 +
   1.232 +static int addk (FuncState *fs, TValue *k, TValue *v) {
   1.233 +  lua_State *L = fs->L;
   1.234 +  TValue *idx = luaH_set(L, fs->h, k);
   1.235 +  Proto *f = fs->f;
   1.236 +  int oldsize = f->sizek;
   1.237 +  if (ttisnumber(idx)) {
   1.238 +    lua_assert(luaO_rawequalObj(&fs->f->k[cast_int(nvalue(idx))], v));
   1.239 +    return cast_int(nvalue(idx));
   1.240 +  }
   1.241 +  else {  /* constant not found; create a new entry */
   1.242 +    setnvalue(idx, cast_num(fs->nk));
   1.243 +    luaM_growvector(L, f->k, fs->nk, f->sizek, TValue,
   1.244 +                    MAXARG_Bx, "constant table overflow");
   1.245 +    while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]);
   1.246 +    setobj(L, &f->k[fs->nk], v);
   1.247 +    luaC_barrier(L, f, v);
   1.248 +    return fs->nk++;
   1.249 +  }
   1.250 +}
   1.251 +
   1.252 +
   1.253 +int luaK_stringK (FuncState *fs, TString *s) {
   1.254 +  TValue o;
   1.255 +  setsvalue(fs->L, &o, s);
   1.256 +  return addk(fs, &o, &o);
   1.257 +}
   1.258 +
   1.259 +
   1.260 +int luaK_numberK (FuncState *fs, lua_Number r) {
   1.261 +  TValue o;
   1.262 +  setnvalue(&o, r);
   1.263 +  return addk(fs, &o, &o);
   1.264 +}
   1.265 +
   1.266 +
   1.267 +static int boolK (FuncState *fs, int b) {
   1.268 +  TValue o;
   1.269 +  setbvalue(&o, b);
   1.270 +  return addk(fs, &o, &o);
   1.271 +}
   1.272 +
   1.273 +
   1.274 +static int nilK (FuncState *fs) {
   1.275 +  TValue k, v;
   1.276 +  setnilvalue(&v);
   1.277 +  /* cannot use nil as key; instead use table itself to represent nil */
   1.278 +  sethvalue(fs->L, &k, fs->h);
   1.279 +  return addk(fs, &k, &v);
   1.280 +}
   1.281 +
   1.282 +
   1.283 +void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) {
   1.284 +  if (e->k == VCALL) {  /* expression is an open function call? */
   1.285 +    SETARG_C(getcode(fs, e), nresults+1);
   1.286 +  }
   1.287 +  else if (e->k == VVARARG) {
   1.288 +    SETARG_B(getcode(fs, e), nresults+1);
   1.289 +    SETARG_A(getcode(fs, e), fs->freereg);
   1.290 +    luaK_reserveregs(fs, 1);
   1.291 +  }
   1.292 +}
   1.293 +
   1.294 +
   1.295 +void luaK_setoneret (FuncState *fs, expdesc *e) {
   1.296 +  if (e->k == VCALL) {  /* expression is an open function call? */
   1.297 +    e->k = VNONRELOC;
   1.298 +    e->u.s.info = GETARG_A(getcode(fs, e));
   1.299 +  }
   1.300 +  else if (e->k == VVARARG) {
   1.301 +    SETARG_B(getcode(fs, e), 2);
   1.302 +    e->k = VRELOCABLE;  /* can relocate its simple result */
   1.303 +  }
   1.304 +}
   1.305 +
   1.306 +
   1.307 +void luaK_dischargevars (FuncState *fs, expdesc *e) {
   1.308 +  switch (e->k) {
   1.309 +    case VLOCAL: {
   1.310 +      e->k = VNONRELOC;
   1.311 +      break;
   1.312 +    }
   1.313 +    case VUPVAL: {
   1.314 +      e->u.s.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.s.info, 0);
   1.315 +      e->k = VRELOCABLE;
   1.316 +      break;
   1.317 +    }
   1.318 +    case VGLOBAL: {
   1.319 +      e->u.s.info = luaK_codeABx(fs, OP_GETGLOBAL, 0, e->u.s.info);
   1.320 +      e->k = VRELOCABLE;
   1.321 +      break;
   1.322 +    }
   1.323 +    case VINDEXED: {
   1.324 +      freereg(fs, e->u.s.aux);
   1.325 +      freereg(fs, e->u.s.info);
   1.326 +      e->u.s.info = luaK_codeABC(fs, OP_GETTABLE, 0, e->u.s.info, e->u.s.aux);
   1.327 +      e->k = VRELOCABLE;
   1.328 +      break;
   1.329 +    }
   1.330 +    case VVARARG:
   1.331 +    case VCALL: {
   1.332 +      luaK_setoneret(fs, e);
   1.333 +      break;
   1.334 +    }
   1.335 +    default: break;  /* there is one value available (somewhere) */
   1.336 +  }
   1.337 +}
   1.338 +
   1.339 +
   1.340 +static int code_label (FuncState *fs, int A, int b, int jump) {
   1.341 +  luaK_getlabel(fs);  /* those instructions may be jump targets */
   1.342 +  return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump);
   1.343 +}
   1.344 +
   1.345 +
   1.346 +static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
   1.347 +  luaK_dischargevars(fs, e);
   1.348 +  switch (e->k) {
   1.349 +    case VNIL: {
   1.350 +      luaK_nil(fs, reg, 1);
   1.351 +      break;
   1.352 +    }
   1.353 +    case VFALSE:  case VTRUE: {
   1.354 +      luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0);
   1.355 +      break;
   1.356 +    }
   1.357 +    case VK: {
   1.358 +      luaK_codeABx(fs, OP_LOADK, reg, e->u.s.info);
   1.359 +      break;
   1.360 +    }
   1.361 +    case VKNUM: {
   1.362 +      luaK_codeABx(fs, OP_LOADK, reg, luaK_numberK(fs, e->u.nval));
   1.363 +      break;
   1.364 +    }
   1.365 +    case VRELOCABLE: {
   1.366 +      Instruction *pc = &getcode(fs, e);
   1.367 +      SETARG_A(*pc, reg);
   1.368 +      break;
   1.369 +    }
   1.370 +    case VNONRELOC: {
   1.371 +      if (reg != e->u.s.info)
   1.372 +        luaK_codeABC(fs, OP_MOVE, reg, e->u.s.info, 0);
   1.373 +      break;
   1.374 +    }
   1.375 +    default: {
   1.376 +      lua_assert(e->k == VVOID || e->k == VJMP);
   1.377 +      return;  /* nothing to do... */
   1.378 +    }
   1.379 +  }
   1.380 +  e->u.s.info = reg;
   1.381 +  e->k = VNONRELOC;
   1.382 +}
   1.383 +
   1.384 +
   1.385 +static void discharge2anyreg (FuncState *fs, expdesc *e) {
   1.386 +  if (e->k != VNONRELOC) {
   1.387 +    luaK_reserveregs(fs, 1);
   1.388 +    discharge2reg(fs, e, fs->freereg-1);
   1.389 +  }
   1.390 +}
   1.391 +
   1.392 +
   1.393 +static void exp2reg (FuncState *fs, expdesc *e, int reg) {
   1.394 +  discharge2reg(fs, e, reg);
   1.395 +  if (e->k == VJMP)
   1.396 +    luaK_concat(fs, &e->t, e->u.s.info);  /* put this jump in `t' list */
   1.397 +  if (hasjumps(e)) {
   1.398 +    int final;  /* position after whole expression */
   1.399 +    int p_f = NO_JUMP;  /* position of an eventual LOAD false */
   1.400 +    int p_t = NO_JUMP;  /* position of an eventual LOAD true */
   1.401 +    if (need_value(fs, e->t) || need_value(fs, e->f)) {
   1.402 +      int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs);
   1.403 +      p_f = code_label(fs, reg, 0, 1);
   1.404 +      p_t = code_label(fs, reg, 1, 0);
   1.405 +      luaK_patchtohere(fs, fj);
   1.406 +    }
   1.407 +    final = luaK_getlabel(fs);
   1.408 +    patchlistaux(fs, e->f, final, reg, p_f);
   1.409 +    patchlistaux(fs, e->t, final, reg, p_t);
   1.410 +  }
   1.411 +  e->f = e->t = NO_JUMP;
   1.412 +  e->u.s.info = reg;
   1.413 +  e->k = VNONRELOC;
   1.414 +}
   1.415 +
   1.416 +
   1.417 +void luaK_exp2nextreg (FuncState *fs, expdesc *e) {
   1.418 +  luaK_dischargevars(fs, e);
   1.419 +  freeexp(fs, e);
   1.420 +  luaK_reserveregs(fs, 1);
   1.421 +  exp2reg(fs, e, fs->freereg - 1);
   1.422 +}
   1.423 +
   1.424 +
   1.425 +int luaK_exp2anyreg (FuncState *fs, expdesc *e) {
   1.426 +  luaK_dischargevars(fs, e);
   1.427 +  if (e->k == VNONRELOC) {
   1.428 +    if (!hasjumps(e)) return e->u.s.info;  /* exp is already in a register */
   1.429 +    if (e->u.s.info >= fs->nactvar) {  /* reg. is not a local? */
   1.430 +      exp2reg(fs, e, e->u.s.info);  /* put value on it */
   1.431 +      return e->u.s.info;
   1.432 +    }
   1.433 +  }
   1.434 +  luaK_exp2nextreg(fs, e);  /* default */
   1.435 +  return e->u.s.info;
   1.436 +}
   1.437 +
   1.438 +
   1.439 +void luaK_exp2val (FuncState *fs, expdesc *e) {
   1.440 +  if (hasjumps(e))
   1.441 +    luaK_exp2anyreg(fs, e);
   1.442 +  else
   1.443 +    luaK_dischargevars(fs, e);
   1.444 +}
   1.445 +
   1.446 +
   1.447 +int luaK_exp2RK (FuncState *fs, expdesc *e) {
   1.448 +  luaK_exp2val(fs, e);
   1.449 +  switch (e->k) {
   1.450 +    case VKNUM:
   1.451 +    case VTRUE:
   1.452 +    case VFALSE:
   1.453 +    case VNIL: {
   1.454 +      if (fs->nk <= MAXINDEXRK) {  /* constant fit in RK operand? */
   1.455 +        e->u.s.info = (e->k == VNIL)  ? nilK(fs) :
   1.456 +                      (e->k == VKNUM) ? luaK_numberK(fs, e->u.nval) :
   1.457 +                                        boolK(fs, (e->k == VTRUE));
   1.458 +        e->k = VK;
   1.459 +        return RKASK(e->u.s.info);
   1.460 +      }
   1.461 +      else break;
   1.462 +    }
   1.463 +    case VK: {
   1.464 +      if (e->u.s.info <= MAXINDEXRK)  /* constant fit in argC? */
   1.465 +        return RKASK(e->u.s.info);
   1.466 +      else break;
   1.467 +    }
   1.468 +    default: break;
   1.469 +  }
   1.470 +  /* not a constant in the right range: put it in a register */
   1.471 +  return luaK_exp2anyreg(fs, e);
   1.472 +}
   1.473 +
   1.474 +
   1.475 +void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
   1.476 +  switch (var->k) {
   1.477 +    case VLOCAL: {
   1.478 +      freeexp(fs, ex);
   1.479 +      exp2reg(fs, ex, var->u.s.info);
   1.480 +      return;
   1.481 +    }
   1.482 +    case VUPVAL: {
   1.483 +      int e = luaK_exp2anyreg(fs, ex);
   1.484 +      luaK_codeABC(fs, OP_SETUPVAL, e, var->u.s.info, 0);
   1.485 +      break;
   1.486 +    }
   1.487 +    case VGLOBAL: {
   1.488 +      int e = luaK_exp2anyreg(fs, ex);
   1.489 +      luaK_codeABx(fs, OP_SETGLOBAL, e, var->u.s.info);
   1.490 +      break;
   1.491 +    }
   1.492 +    case VINDEXED: {
   1.493 +      int e = luaK_exp2RK(fs, ex);
   1.494 +      luaK_codeABC(fs, OP_SETTABLE, var->u.s.info, var->u.s.aux, e);
   1.495 +      break;
   1.496 +    }
   1.497 +    default: {
   1.498 +      lua_assert(0);  /* invalid var kind to store */
   1.499 +      break;
   1.500 +    }
   1.501 +  }
   1.502 +  freeexp(fs, ex);
   1.503 +}
   1.504 +
   1.505 +
   1.506 +void luaK_self (FuncState *fs, expdesc *e, expdesc *key) {
   1.507 +  int func;
   1.508 +  luaK_exp2anyreg(fs, e);
   1.509 +  freeexp(fs, e);
   1.510 +  func = fs->freereg;
   1.511 +  luaK_reserveregs(fs, 2);
   1.512 +  luaK_codeABC(fs, OP_SELF, func, e->u.s.info, luaK_exp2RK(fs, key));
   1.513 +  freeexp(fs, key);
   1.514 +  e->u.s.info = func;
   1.515 +  e->k = VNONRELOC;
   1.516 +}
   1.517 +
   1.518 +
   1.519 +static void invertjump (FuncState *fs, expdesc *e) {
   1.520 +  Instruction *pc = getjumpcontrol(fs, e->u.s.info);
   1.521 +  lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET &&
   1.522 +                                           GET_OPCODE(*pc) != OP_TEST);
   1.523 +  SETARG_A(*pc, !(GETARG_A(*pc)));
   1.524 +}
   1.525 +
   1.526 +
   1.527 +static int jumponcond (FuncState *fs, expdesc *e, int cond) {
   1.528 +  if (e->k == VRELOCABLE) {
   1.529 +    Instruction ie = getcode(fs, e);
   1.530 +    if (GET_OPCODE(ie) == OP_NOT) {
   1.531 +      fs->pc--;  /* remove previous OP_NOT */
   1.532 +      return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond);
   1.533 +    }
   1.534 +    /* else go through */
   1.535 +  }
   1.536 +  discharge2anyreg(fs, e);
   1.537 +  freeexp(fs, e);
   1.538 +  return condjump(fs, OP_TESTSET, NO_REG, e->u.s.info, cond);
   1.539 +}
   1.540 +
   1.541 +
   1.542 +void luaK_goiftrue (FuncState *fs, expdesc *e) {
   1.543 +  int pc;  /* pc of last jump */
   1.544 +  luaK_dischargevars(fs, e);
   1.545 +  switch (e->k) {
   1.546 +    case VK: case VKNUM: case VTRUE: {
   1.547 +      pc = NO_JUMP;  /* always true; do nothing */
   1.548 +      break;
   1.549 +    }
   1.550 +    case VFALSE: {
   1.551 +      pc = luaK_jump(fs);  /* always jump */
   1.552 +      break;
   1.553 +    }
   1.554 +    case VJMP: {
   1.555 +      invertjump(fs, e);
   1.556 +      pc = e->u.s.info;
   1.557 +      break;
   1.558 +    }
   1.559 +    default: {
   1.560 +      pc = jumponcond(fs, e, 0);
   1.561 +      break;
   1.562 +    }
   1.563 +  }
   1.564 +  luaK_concat(fs, &e->f, pc);  /* insert last jump in `f' list */
   1.565 +  luaK_patchtohere(fs, e->t);
   1.566 +  e->t = NO_JUMP;
   1.567 +}
   1.568 +
   1.569 +
   1.570 +static void luaK_goiffalse (FuncState *fs, expdesc *e) {
   1.571 +  int pc;  /* pc of last jump */
   1.572 +  luaK_dischargevars(fs, e);
   1.573 +  switch (e->k) {
   1.574 +    case VNIL: case VFALSE: {
   1.575 +      pc = NO_JUMP;  /* always false; do nothing */
   1.576 +      break;
   1.577 +    }
   1.578 +    case VTRUE: {
   1.579 +      pc = luaK_jump(fs);  /* always jump */
   1.580 +      break;
   1.581 +    }
   1.582 +    case VJMP: {
   1.583 +      pc = e->u.s.info;
   1.584 +      break;
   1.585 +    }
   1.586 +    default: {
   1.587 +      pc = jumponcond(fs, e, 1);
   1.588 +      break;
   1.589 +    }
   1.590 +  }
   1.591 +  luaK_concat(fs, &e->t, pc);  /* insert last jump in `t' list */
   1.592 +  luaK_patchtohere(fs, e->f);
   1.593 +  e->f = NO_JUMP;
   1.594 +}
   1.595 +
   1.596 +
   1.597 +static void codenot (FuncState *fs, expdesc *e) {
   1.598 +  luaK_dischargevars(fs, e);
   1.599 +  switch (e->k) {
   1.600 +    case VNIL: case VFALSE: {
   1.601 +      e->k = VTRUE;
   1.602 +      break;
   1.603 +    }
   1.604 +    case VK: case VKNUM: case VTRUE: {
   1.605 +      e->k = VFALSE;
   1.606 +      break;
   1.607 +    }
   1.608 +    case VJMP: {
   1.609 +      invertjump(fs, e);
   1.610 +      break;
   1.611 +    }
   1.612 +    case VRELOCABLE:
   1.613 +    case VNONRELOC: {
   1.614 +      discharge2anyreg(fs, e);
   1.615 +      freeexp(fs, e);
   1.616 +      e->u.s.info = luaK_codeABC(fs, OP_NOT, 0, e->u.s.info, 0);
   1.617 +      e->k = VRELOCABLE;
   1.618 +      break;
   1.619 +    }
   1.620 +    default: {
   1.621 +      lua_assert(0);  /* cannot happen */
   1.622 +      break;
   1.623 +    }
   1.624 +  }
   1.625 +  /* interchange true and false lists */
   1.626 +  { int temp = e->f; e->f = e->t; e->t = temp; }
   1.627 +  removevalues(fs, e->f);
   1.628 +  removevalues(fs, e->t);
   1.629 +}
   1.630 +
   1.631 +
   1.632 +void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
   1.633 +  t->u.s.aux = luaK_exp2RK(fs, k);
   1.634 +  t->k = VINDEXED;
   1.635 +}
   1.636 +
   1.637 +
   1.638 +static int constfolding (OpCode op, expdesc *e1, expdesc *e2) {
   1.639 +  lua_Number v1, v2, r;
   1.640 +  if (!isnumeral(e1) || !isnumeral(e2)) return 0;
   1.641 +  v1 = e1->u.nval;
   1.642 +  v2 = e2->u.nval;
   1.643 +  switch (op) {
   1.644 +    case OP_ADD: r = luai_numadd(v1, v2); break;
   1.645 +    case OP_SUB: r = luai_numsub(v1, v2); break;
   1.646 +    case OP_MUL: r = luai_nummul(v1, v2); break;
   1.647 +    case OP_DIV:
   1.648 +      if (v2 == 0) return 0;  /* do not attempt to divide by 0 */
   1.649 +      r = luai_numdiv(v1, v2); break;
   1.650 +    case OP_MOD:
   1.651 +      if (v2 == 0) return 0;  /* do not attempt to divide by 0 */
   1.652 +      r = luai_nummod(v1, v2); break;
   1.653 +    case OP_POW: r = luai_numpow(v1, v2); break;
   1.654 +    case OP_UNM: r = luai_numunm(v1); break;
   1.655 +    case OP_LEN: return 0;  /* no constant folding for 'len' */
   1.656 +    default: lua_assert(0); r = 0; break;
   1.657 +  }
   1.658 +  if (luai_numisnan(r)) return 0;  /* do not attempt to produce NaN */
   1.659 +  e1->u.nval = r;
   1.660 +  return 1;
   1.661 +}
   1.662 +
   1.663 +
   1.664 +static void codearith (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) {
   1.665 +  if (constfolding(op, e1, e2))
   1.666 +    return;
   1.667 +  else {
   1.668 +    int o2 = (op != OP_UNM && op != OP_LEN) ? luaK_exp2RK(fs, e2) : 0;
   1.669 +    int o1 = luaK_exp2RK(fs, e1);
   1.670 +    if (o1 > o2) {
   1.671 +      freeexp(fs, e1);
   1.672 +      freeexp(fs, e2);
   1.673 +    }
   1.674 +    else {
   1.675 +      freeexp(fs, e2);
   1.676 +      freeexp(fs, e1);
   1.677 +    }
   1.678 +    e1->u.s.info = luaK_codeABC(fs, op, 0, o1, o2);
   1.679 +    e1->k = VRELOCABLE;
   1.680 +  }
   1.681 +}
   1.682 +
   1.683 +
   1.684 +static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1,
   1.685 +                                                          expdesc *e2) {
   1.686 +  int o1 = luaK_exp2RK(fs, e1);
   1.687 +  int o2 = luaK_exp2RK(fs, e2);
   1.688 +  freeexp(fs, e2);
   1.689 +  freeexp(fs, e1);
   1.690 +  if (cond == 0 && op != OP_EQ) {
   1.691 +    int temp;  /* exchange args to replace by `<' or `<=' */
   1.692 +    temp = o1; o1 = o2; o2 = temp;  /* o1 <==> o2 */
   1.693 +    cond = 1;
   1.694 +  }
   1.695 +  e1->u.s.info = condjump(fs, op, cond, o1, o2);
   1.696 +  e1->k = VJMP;
   1.697 +}
   1.698 +
   1.699 +
   1.700 +void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) {
   1.701 +  expdesc e2;
   1.702 +  e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0;
   1.703 +  switch (op) {
   1.704 +    case OPR_MINUS: {
   1.705 +      if (!isnumeral(e))
   1.706 +        luaK_exp2anyreg(fs, e);  /* cannot operate on non-numeric constants */
   1.707 +      codearith(fs, OP_UNM, e, &e2);
   1.708 +      break;
   1.709 +    }
   1.710 +    case OPR_NOT: codenot(fs, e); break;
   1.711 +    case OPR_LEN: {
   1.712 +      luaK_exp2anyreg(fs, e);  /* cannot operate on constants */
   1.713 +      codearith(fs, OP_LEN, e, &e2);
   1.714 +      break;
   1.715 +    }
   1.716 +    default: lua_assert(0);
   1.717 +  }
   1.718 +}
   1.719 +
   1.720 +
   1.721 +void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
   1.722 +  switch (op) {
   1.723 +    case OPR_AND: {
   1.724 +      luaK_goiftrue(fs, v);
   1.725 +      break;
   1.726 +    }
   1.727 +    case OPR_OR: {
   1.728 +      luaK_goiffalse(fs, v);
   1.729 +      break;
   1.730 +    }
   1.731 +    case OPR_CONCAT: {
   1.732 +      luaK_exp2nextreg(fs, v);  /* operand must be on the `stack' */
   1.733 +      break;
   1.734 +    }
   1.735 +    case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV:
   1.736 +    case OPR_MOD: case OPR_POW: {
   1.737 +      if (!isnumeral(v)) luaK_exp2RK(fs, v);
   1.738 +      break;
   1.739 +    }
   1.740 +    default: {
   1.741 +      luaK_exp2RK(fs, v);
   1.742 +      break;
   1.743 +    }
   1.744 +  }
   1.745 +}
   1.746 +
   1.747 +
   1.748 +void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) {
   1.749 +  switch (op) {
   1.750 +    case OPR_AND: {
   1.751 +      lua_assert(e1->t == NO_JUMP);  /* list must be closed */
   1.752 +      luaK_dischargevars(fs, e2);
   1.753 +      luaK_concat(fs, &e2->f, e1->f);
   1.754 +      *e1 = *e2;
   1.755 +      break;
   1.756 +    }
   1.757 +    case OPR_OR: {
   1.758 +      lua_assert(e1->f == NO_JUMP);  /* list must be closed */
   1.759 +      luaK_dischargevars(fs, e2);
   1.760 +      luaK_concat(fs, &e2->t, e1->t);
   1.761 +      *e1 = *e2;
   1.762 +      break;
   1.763 +    }
   1.764 +    case OPR_CONCAT: {
   1.765 +      luaK_exp2val(fs, e2);
   1.766 +      if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) {
   1.767 +        lua_assert(e1->u.s.info == GETARG_B(getcode(fs, e2))-1);
   1.768 +        freeexp(fs, e1);
   1.769 +        SETARG_B(getcode(fs, e2), e1->u.s.info);
   1.770 +        e1->k = VRELOCABLE; e1->u.s.info = e2->u.s.info;
   1.771 +      }
   1.772 +      else {
   1.773 +        luaK_exp2nextreg(fs, e2);  /* operand must be on the 'stack' */
   1.774 +        codearith(fs, OP_CONCAT, e1, e2);
   1.775 +      }
   1.776 +      break;
   1.777 +    }
   1.778 +    case OPR_ADD: codearith(fs, OP_ADD, e1, e2); break;
   1.779 +    case OPR_SUB: codearith(fs, OP_SUB, e1, e2); break;
   1.780 +    case OPR_MUL: codearith(fs, OP_MUL, e1, e2); break;
   1.781 +    case OPR_DIV: codearith(fs, OP_DIV, e1, e2); break;
   1.782 +    case OPR_MOD: codearith(fs, OP_MOD, e1, e2); break;
   1.783 +    case OPR_POW: codearith(fs, OP_POW, e1, e2); break;
   1.784 +    case OPR_EQ: codecomp(fs, OP_EQ, 1, e1, e2); break;
   1.785 +    case OPR_NE: codecomp(fs, OP_EQ, 0, e1, e2); break;
   1.786 +    case OPR_LT: codecomp(fs, OP_LT, 1, e1, e2); break;
   1.787 +    case OPR_LE: codecomp(fs, OP_LE, 1, e1, e2); break;
   1.788 +    case OPR_GT: codecomp(fs, OP_LT, 0, e1, e2); break;
   1.789 +    case OPR_GE: codecomp(fs, OP_LE, 0, e1, e2); break;
   1.790 +    default: lua_assert(0);
   1.791 +  }
   1.792 +}
   1.793 +
   1.794 +
   1.795 +void luaK_fixline (FuncState *fs, int line) {
   1.796 +  fs->f->lineinfo[fs->pc - 1] = line;
   1.797 +}
   1.798 +
   1.799 +
   1.800 +static int luaK_code (FuncState *fs, Instruction i, int line) {
   1.801 +  Proto *f = fs->f;
   1.802 +  dischargejpc(fs);  /* `pc' will change */
   1.803 +  /* put new instruction in code array */
   1.804 +  luaM_growvector(fs->L, f->code, fs->pc, f->sizecode, Instruction,
   1.805 +                  MAX_INT, "code size overflow");
   1.806 +  f->code[fs->pc] = i;
   1.807 +  /* save corresponding line information */
   1.808 +  luaM_growvector(fs->L, f->lineinfo, fs->pc, f->sizelineinfo, int,
   1.809 +                  MAX_INT, "code size overflow");
   1.810 +  f->lineinfo[fs->pc] = line;
   1.811 +  return fs->pc++;
   1.812 +}
   1.813 +
   1.814 +
   1.815 +int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) {
   1.816 +  lua_assert(getOpMode(o) == iABC);
   1.817 +  lua_assert(getBMode(o) != OpArgN || b == 0);
   1.818 +  lua_assert(getCMode(o) != OpArgN || c == 0);
   1.819 +  return luaK_code(fs, CREATE_ABC(o, a, b, c), fs->ls->lastline);
   1.820 +}
   1.821 +
   1.822 +
   1.823 +int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) {
   1.824 +  lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx);
   1.825 +  lua_assert(getCMode(o) == OpArgN);
   1.826 +  return luaK_code(fs, CREATE_ABx(o, a, bc), fs->ls->lastline);
   1.827 +}
   1.828 +
   1.829 +
   1.830 +void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) {
   1.831 +  int c =  (nelems - 1)/LFIELDS_PER_FLUSH + 1;
   1.832 +  int b = (tostore == LUA_MULTRET) ? 0 : tostore;
   1.833 +  lua_assert(tostore != 0);
   1.834 +  if (c <= MAXARG_C)
   1.835 +    luaK_codeABC(fs, OP_SETLIST, base, b, c);
   1.836 +  else {
   1.837 +    luaK_codeABC(fs, OP_SETLIST, base, b, 0);
   1.838 +    luaK_code(fs, cast(Instruction, c), fs->ls->lastline);
   1.839 +  }
   1.840 +  fs->freereg = base + 1;  /* free registers with list values */
   1.841 +}
   1.842 +