Browse Source

new implementation for the Virtual Machine

Roberto Ierusalimschy 24 năm trước cách đây
mục cha
commit
762d059a13
15 tập tin đã thay đổi với 1593 bổ sung1438 xóa
  1. 12 6
      lapi.c
  2. 566 479
      lcode.c
  3. 21 28
      lcode.h
  4. 195 165
      ldebug.c
  5. 24 3
      ldebug.h
  6. 4 7
      lfunc.c
  7. 5 3
      lgc.c
  8. 5 84
      llimits.h
  9. 3 5
      lobject.h
  10. 127 92
      lopcodes.h
  11. 322 227
      lparser.c
  12. 19 13
      lparser.h
  13. 56 77
      ltests.c
  14. 231 245
      lvm.c
  15. 3 4
      lvm.h

+ 12 - 6
lapi.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lapi.c,v 1.140 2001/04/17 17:35:54 roberto Exp roberto $
+** $Id: lapi.c,v 1.141 2001/04/23 16:35:45 roberto Exp roberto $
 ** Lua API
 ** See Copyright Notice in lua.h
 */
@@ -184,9 +184,10 @@ LUA_API int lua_iscfunction (lua_State *L, int index) {
 LUA_API int lua_isnumber (lua_State *L, int index) {
   TObject *o;
   int i;
+  TObject n;
   lua_lock(L);
   o = luaA_indexAcceptable(L, index);
-  i = (o == NULL) ? 0 : (tonumber(o) == 0);
+  i = (o != NULL && (ttype(o) == LUA_TNUMBER || luaV_tonumber(o, &n)));
   lua_unlock(L);
   return i;
 }
@@ -234,13 +235,18 @@ LUA_API int lua_lessthan (lua_State *L, int index1, int index2) {
 
 
 LUA_API lua_Number lua_tonumber (lua_State *L, int index) {
-  StkId o;
-  lua_Number n;
+  const TObject *o;
+  TObject n;
+  lua_Number res;
   lua_lock(L);
   o = luaA_indexAcceptable(L, index);
-  n = (o == NULL || tonumber(o)) ? 0 : nvalue(o);
+  if (o != NULL &&
+      (ttype(o) == LUA_TNUMBER || (o = luaV_tonumber(o, &n)) != NULL))
+    res = nvalue(o);
+  else
+    res = 0;
   lua_unlock(L);
-  return n;
+  return res;
 }
 
 LUA_API const l_char *lua_tostring (lua_State *L, int index) {

+ 566 - 479
lcode.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lcode.c,v 1.67 2001/04/06 18:25:00 roberto Exp roberto $
+** $Id: lcode.c,v 1.68 2001/04/23 16:35:45 roberto Exp roberto $
 ** Code generator for Lua
 ** See Copyright Notice in lua.h
 */
@@ -11,6 +11,7 @@
 #include "lua.h"
 
 #include "lcode.h"
+#include "ldebug.h"
 #include "ldo.h"
 #include "llex.h"
 #include "lmem.h"
@@ -19,6 +20,12 @@
 #include "lparser.h"
 
 
+#define hasjumps(e)	((e)->t != (e)->f)
+
+#define getcode(fs,e)	((fs)->f->code[(e)->u.i.info])
+
+
+
 void luaK_error (LexState *ls, const l_char *msg) {
   luaX_error(ls, msg, ls->t.token);
 }
@@ -33,12 +40,27 @@ static Instruction previous_instruction (FuncState *fs) {
   if (fs->pc > fs->lasttarget)  /* no jumps to current position? */
     return fs->f->code[fs->pc-1];  /* returns previous instruction */
   else
-    return CREATE_0(-1);  /* no optimizations after an invalid instruction */
+    return (Instruction)(-1);/* no optimizations after an invalid instruction */
+}
+
+
+void luaK_nil (FuncState *fs, int from, int n) {
+  Instruction previous = previous_instruction(fs);
+  if (GET_OPCODE(previous) == OP_LOADNIL) {
+    int pfrom = GETARG_A(previous);
+    int pto = GETARG_B(previous);
+    if (pfrom <= from && from <= pto+1) {  /* can connect both? */
+      if (from+n-1 > pto)
+        SETARG_B(fs->f->code[fs->pc-1], from+n-1);
+      return;
+    }
+  }
+  luaK_codeABC(fs, OP_LOADNIL, from, from+n-1, 0);  /* else no optimization */
 }
 
 
 int luaK_jump (FuncState *fs) {
-  int j = luaK_code1(fs, OP_JMP, NO_JUMP);
+  int j = luaK_codeAsBc(fs, OP_JMP, 0, NO_JUMP);
   if (j == fs->lasttarget) {  /* possible jumps to this jump? */
     luaK_concat(fs, &j, fs->jlt);  /* keep them on hold */
     fs->jlt = NO_JUMP;
@@ -47,36 +69,33 @@ int luaK_jump (FuncState *fs) {
 }
 
 
+static int luaK_condjump (FuncState *fs, OpCode op, int B, int C) {
+  luaK_codeABC(fs, op, NO_REG, B, C);
+  return luaK_codeAsBc(fs, OP_CJMP, 0, NO_JUMP);
+}
+
+
 static void luaK_fixjump (FuncState *fs, int pc, int dest) {
   Instruction *jmp = &fs->f->code[pc];
   if (dest == NO_JUMP)
-    SETARG_S(*jmp, NO_JUMP);  /* point to itself to represent end of list */
+    SETARG_sBc(*jmp, NO_JUMP);  /* point to itself to represent end of list */
   else {  /* jump is relative to position following jump instruction */
     int offset = dest-(pc+1);
-    if (abs(offset) > MAXARG_S)
+    if (abs(offset) > MAXARG_sBc)
       luaK_error(fs->ls, l_s("control structure too long"));
-    SETARG_S(*jmp, offset);
+    SETARG_sBc(*jmp, offset);
   }
 }
 
 
 /*
-** prep-for instructions (OP_FORPREP & OP_LFORPREP) have a negated jump,
+** prep-for instructions (OP_FORPREP & OP_TFORPREP) have a negated jump,
 ** as they simulate the real jump...
 */
 void luaK_fixfor (FuncState *fs, int pc, int dest) {
   Instruction *jmp = &fs->f->code[pc];
   int offset = dest-(pc+1);
-  SETARG_S(*jmp, -offset);
-}
-
-
-static int luaK_getjump (FuncState *fs, int pc) {
-  int offset = GETARG_S(fs->f->code[pc]);
-  if (offset == NO_JUMP)  /* point to itself represents end of list */
-    return NO_JUMP;  /* end of list */
-  else
-    return (pc+1)+offset;  /* turn offset into absolute position */
+  SETARG_sBc(*jmp, -offset);
 }
 
 
@@ -96,609 +115,677 @@ int luaK_getlabel (FuncState *fs) {
 }
 
 
-void luaK_deltastack (FuncState *fs, int delta) {
-  fs->stacklevel += delta;
-  if (fs->stacklevel > fs->f->maxstacksize) {
-    if (fs->stacklevel > MAXSTACK)
-      luaK_error(fs->ls, l_s("function or expression too complex"));
-    fs->f->maxstacksize = (short)fs->stacklevel;
-  }
+static int luaK_getjump (FuncState *fs, int pc) {
+  int offset = GETARG_sBc(fs->f->code[pc]);
+  if (offset == NO_JUMP)  /* point to itself represents end of list */
+    return NO_JUMP;  /* end of list */
+  else
+    return (pc+1)+offset;  /* turn offset into absolute position */
 }
 
 
-void luaK_kstr (LexState *ls, int c) {
-  luaK_code1(ls->fs, OP_PUSHSTRING, c);
+static Instruction *getjumpcontrol (FuncState *fs, int pc) {
+  Instruction *pi = &fs->f->code[pc];
+  OpCode op = GET_OPCODE(*pi);
+  if (op == OP_CJMP)
+    return pi-1;
+  else {
+    lua_assert(op == OP_JMP || op == OP_FORLOOP || op == OP_TFORLOOP);
+    return pi;
+  }
 }
 
 
-static int number_constant (FuncState *fs, lua_Number r) {
-  /* check whether `r' has appeared within the last LOOKBACKNUMS entries */
-  Proto *f = fs->f;
-  int c = fs->nknum;
-  int lim = c < LOOKBACKNUMS ? 0 : c-LOOKBACKNUMS;
-  while (--c >= lim)
-    if (f->knum[c] == r) return c;
-  /* not found; create a new entry */
-  luaM_growvector(fs->L, f->knum, fs->nknum, f->sizeknum, lua_Number,
-                  MAXARG_U, l_s("constant table overflow"));
-  c = fs->nknum++;
-  f->knum[c] = r;
-  return c;
+static int need_value (FuncState *fs, int list, OpCode op) {
+  /* check whether list has any jump different from `op' */
+  for (; list != NO_JUMP; list = luaK_getjump(fs, list))
+    if (GET_OPCODE(*getjumpcontrol(fs, list)) != op) return 1;
+  return 0;  /* not found */
 }
 
 
-void luaK_number (FuncState *fs, lua_Number f) {
-  if (f <= (lua_Number)MAXARG_S && (lua_Number)(int)f == f)
-    luaK_code1(fs, OP_PUSHINT, (int)f);  /* f has a short integer value */
-  else
-    luaK_code1(fs, OP_PUSHNUM, number_constant(fs, f));
+static void luaK_patchlistaux (FuncState *fs, int list,
+          int ttarget, int treg, int ftarget, int freg, int dtarget) {
+  while (list != NO_JUMP) {
+    int next = luaK_getjump(fs, list);
+    Instruction *i = getjumpcontrol(fs, list);
+    switch (GET_OPCODE(*i)) {
+      case OP_TESTT: {
+        SETARG_A(*i, treg);
+        luaK_fixjump(fs, list, ttarget);
+        break;
+      }
+      case OP_TESTF: {
+        SETARG_A(*i, freg);
+        luaK_fixjump(fs, list, ftarget);
+        break;
+      }
+      default: {
+        luaK_fixjump(fs, list, dtarget);  /* jump to default target */
+        break;
+      }
+    }
+    list = next;
+  }
 }
 
 
-void luaK_adjuststack (FuncState *fs, int n) {
-  if (n > 0)
-    luaK_code1(fs, OP_POP, n);
+void luaK_patchlist (FuncState *fs, int list, int target) {
+  if (target == fs->lasttarget)  /* same target that list `jlt'? */
+    luaK_concat(fs, &fs->jlt, list);  /* delay fixing */
   else
-    luaK_code1(fs, OP_PUSHNIL, -n);
+    luaK_patchlistaux(fs, list, target, NO_REG, target, NO_REG, target);
 }
 
 
-int luaK_lastisopen (FuncState *fs) {
-  /* check whether last instruction is an open function call */
-  Instruction i = previous_instruction(fs);
-  if (GET_OPCODE(i) == OP_CALL && GETARG_B(i) == MULT_RET)
-    return 1;
-  else return 0;
+void luaK_concat (FuncState *fs, int *l1, int l2) {
+  if (*l1 == NO_JUMP)
+    *l1 = l2;
+  else {
+    int list = *l1;
+    int next;
+    while ((next = luaK_getjump(fs, list)) != NO_JUMP)  /* find last element */
+      list = next;
+    luaK_fixjump(fs, list, l2);
+  }
 }
 
 
-void luaK_setcallreturns (FuncState *fs, int nresults) {
-  if (luaK_lastisopen(fs)) {  /* expression is an open function call? */
-    SETARG_B(fs->f->code[fs->pc-1], nresults);  /* set number of results */
-    luaK_deltastack(fs, nresults);  /* push results */
+void luaK_reserveregs (FuncState *fs, int n) {
+  fs->freereg += n;
+  if (fs->freereg > fs->f->maxstacksize) {
+    if (fs->freereg >= MAXSTACK)
+      luaK_error(fs->ls, l_s("function or expression too complex"));
+    fs->f->maxstacksize = (short)fs->freereg;
   }
 }
 
 
-static int discharge (FuncState *fs, expdesc *var) {
-  switch (var->k) {
-    case VLOCAL:
-      luaK_code1(fs, OP_GETLOCAL, var->u.index);
-      break;
-    case VGLOBAL:
-      luaK_code1(fs, OP_GETGLOBAL, var->u.index);
-      break;
-    case VINDEXED:
-      luaK_code0(fs, OP_GETTABLE);
-      break;
-    case VEXP:
-      return 0;  /* nothing to do */
+static void freereg (FuncState *fs, int reg) {
+  if (reg >= fs->nactloc && reg < MAXSTACK) {
+    fs->freereg--;
+    lua_assert(reg == fs->freereg);
   }
-  var->k = VEXP;
-  var->u.l.t = var->u.l.f = NO_JUMP;
-  return 1;
 }
 
 
-static void discharge1 (FuncState *fs, expdesc *var) {
-  discharge(fs, var);
- /* if it has jumps then it is already discharged */
-  if (var->u.l.t == NO_JUMP && var->u.l.f  == NO_JUMP)
-    luaK_setcallreturns(fs, 1);  /* call must return 1 value */
+static void freeexp (FuncState *fs, expdesc *e) {
+  if (e->k == VNONRELOC)
+    freereg(fs, e->u.i.info);
 }
 
 
-void luaK_storevar (LexState *ls, const expdesc *var) {
-  FuncState *fs = ls->fs;
-  switch (var->k) {
-    case VLOCAL:
-      luaK_code1(fs, OP_SETLOCAL, var->u.index);
-      break;
-    case VGLOBAL:
-      luaK_code1(fs, OP_SETGLOBAL, var->u.index);
-      break;
-    case VINDEXED:  /* table is at top-3; pop 3 elements after operation */
-      luaK_code2(fs, OP_SETTABLE, 3, 3);
-      break;
-    default:
-      lua_assert(0);  /* invalid var kind to store */
+static int addk (FuncState *fs, TObject *k) {
+  Proto *f = fs->f;
+  luaM_growvector(fs->L, f->k, fs->nk, f->sizek, TObject,
+                  MAXARG_Bc, l_s("constant table overflow"));
+  setobj(&f->k[fs->nk], k);
+  return fs->nk++;
+}
+
+
+int luaK_stringk (FuncState *fs, TString *s) {
+  Proto *f = fs->f;
+  int c = s->u.s.constindex;
+  if (c >= fs->nk || ttype(&f->k[c]) != LUA_TSTRING || tsvalue(&f->k[c]) != s) {
+    TObject o;
+    setsvalue(&o, s);
+    c = addk(fs, &o);
+    s->u.s.constindex = c;  /* hint for next time */
   }
+  return c;
 }
 
 
-static OpCode invertjump (OpCode op) {
-  switch (op) {
-    case OP_JMPNE: return OP_JMPEQ;
-    case OP_JMPEQ: return OP_JMPNE;
-    case OP_JMPLT: return OP_JMPGE;
-    case OP_JMPLE: return OP_JMPGT;
-    case OP_JMPGT: return OP_JMPLE;
-    case OP_JMPGE: return OP_JMPLT;
-    case OP_JMPT: case OP_JMPONT:  return OP_JMPF;
-    case OP_JMPF: case OP_JMPONF:  return OP_JMPT;
-    default:
-      lua_assert(0);  /* invalid jump instruction */
-      return OP_JMP;  /* to avoid warnings */
+static int number_constant (FuncState *fs, lua_Number r) {
+  /* check whether `r' has appeared within the last LOOKBACKNUMS entries */
+  TObject o;
+  Proto *f = fs->f;
+  int c = fs->nk;
+  int lim = c < LOOKBACKNUMS ? 0 : c-LOOKBACKNUMS;
+  while (--c >= lim) {
+    if (ttype(&f->k[c]) == LUA_TNUMBER && nvalue(&f->k[c]) == r)
+      return c;
   }
+  /* not found; create a new entry */
+  setnvalue(&o, r);
+  return addk(fs, &o);
 }
 
 
-static void luaK_patchlistaux (FuncState *fs, int list, int target,
-                               OpCode special, int special_target) {
-  Instruction *code = fs->f->code;
-  while (list != NO_JUMP) {
-    int next = luaK_getjump(fs, list);
-    Instruction *i = &code[list];
-    OpCode op = GET_OPCODE(*i);
-    if (op == special)  /* this `op' already has a value */
-      luaK_fixjump(fs, list, special_target);
-    else {
-      luaK_fixjump(fs, list, target);  /* do the patch */
-      if (op == OP_JMPONT)  /* remove eventual values */
-        SET_OPCODE(*i, OP_JMPT);
-      else if (op == OP_JMPONF)
-        SET_OPCODE(*i, OP_JMPF);
+void luaK_setcallreturns (FuncState *fs, expdesc *e, int nresults) {
+  if (e->k == VCALL) {  /* expression is an open function call? */
+    SETARG_C(getcode(fs, e), nresults);  /* set number of results */
+    if (nresults == 1) {  /* `regular' expression? */
+      e->k = VNONRELOC;
+      e->u.i.info = GETARG_A(getcode(fs, e));
     }
-    list = next;
   }
 }
 
 
-void luaK_patchlist (FuncState *fs, int list, int target) {
-  if (target == fs->lasttarget)  /* same target that list `jlt'? */
-    luaK_concat(fs, &fs->jlt, list);  /* delay fixing */
-  else
-    luaK_patchlistaux(fs, list, target, OP_ADD, 0);
+static void dischargevars (FuncState *fs, expdesc *e) {
+  switch (e->k) {
+    case VLOCAL: {
+      e->k = VNONRELOC;
+      break;
+    }
+    case VGLOBAL: {
+      e->u.i.info = luaK_codeABc(fs, OP_GETGLOBAL, 0, e->u.i.info);
+      e->k = VRELOCABLE;
+      break;
+    }
+    case VINDEXED: {
+      freereg(fs, e->u.i.aux);
+      freereg(fs, e->u.i.info);
+      e->u.i.info = luaK_codeABC(fs, OP_GETTABLE, 0, e->u.i.info, e->u.i.aux);
+      e->k = VRELOCABLE;
+      break;
+    }
+    case VCALL: {
+      luaK_setcallreturns(fs, e, 1);
+      break;
+    }
+    default: break;  /* there is one value available (somewhere) */
+  }
 }
 
 
-static int need_value (FuncState *fs, int list, OpCode hasvalue) {
-  /* check whether list has a jump without a value */
-  for (; list != NO_JUMP; list = luaK_getjump(fs, list))
-    if (GET_OPCODE(fs->f->code[list]) != hasvalue) return 1;
-  return 0;  /* not found */
+static int code_label (FuncState *fs, OpCode op, int A, int sBc) {
+  luaK_getlabel(fs);  /* those instructions may be jump targets */
+  return luaK_codeAsBc(fs, op, A, sBc);
 }
 
 
-void luaK_concat (FuncState *fs, int *l1, int l2) {
-  if (*l1 == NO_JUMP)
-    *l1 = l2;
-  else {
-    int list = *l1;
-    int next;
-    while ((next = luaK_getjump(fs, list)) != NO_JUMP)  /* find last element */
-      list = next;
-    luaK_fixjump(fs, list, l2);
+static void dischargejumps (FuncState *fs, expdesc *e, int reg) {
+  if (hasjumps(e)) {
+    int final;  /* position after whole expression */
+    int p_nil = NO_JUMP;  /* position of an eventual PUSHNIL */
+    int p_1 = NO_JUMP;  /* position of an eventual PUSHINT */
+    if (need_value(fs, e->f, OP_TESTF) || need_value(fs, e->t, OP_TESTT)) {
+      /* expression needs values */
+      if (e->k != VJMP)
+        code_label(fs, OP_JMP, 0, 2);  /* to jump over both pushes */
+      p_nil = code_label(fs, OP_NILJMP, reg, 0);
+      p_1 = code_label(fs, OP_LOADINT, reg, 1);
+    }
+    final = luaK_getlabel(fs);
+    luaK_patchlistaux(fs, e->f, p_nil, NO_REG, final,    reg, p_nil);
+    luaK_patchlistaux(fs, e->t, final,    reg,   p_1, NO_REG,   p_1);
   }
+  e->f = e->t = NO_JUMP;
 }
 
 
-static void luaK_testgo (FuncState *fs, expdesc *v, int invert, OpCode jump) {
-  int prevpos;  /* position of last instruction */
-  Instruction *previous;
-  int *golist, *exitlist;
-  if (!invert) {
-    golist = &v->u.l.f;    /* go if false */
-    exitlist = &v->u.l.t;  /* exit if true */
-  }
-  else {
-    golist = &v->u.l.t;    /* go if true */
-    exitlist = &v->u.l.f;  /* exit if false */
+static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
+  dischargevars(fs, e);
+  switch (e->k) {
+    case VNIL: {
+      luaK_nil(fs, reg, 1);
+      break;
+    }
+    case VNUMBER: {
+      lua_Number f = e->u.n;
+      int i = (int)f;
+      if ((lua_Number)i == f && -MAXARG_sBc <= i && i <= MAXARG_sBc)
+        luaK_codeAsBc(fs, OP_LOADINT, reg, i);  /* f has a small int value */
+      else
+        luaK_codeABc(fs, OP_LOADK, reg, number_constant(fs, f));
+      break;
+    }
+    case VK: {
+      luaK_codeABc(fs, OP_LOADK, reg, e->u.i.info);
+      break;
+    }
+    case VRELOCABLE: {
+      Instruction *pc = &getcode(fs, e);
+      SETARG_A(*pc, reg);
+      break;
+    }
+    default: return;
   }
-  discharge1(fs, v);
-  prevpos = fs->pc-1;
-  previous = &fs->f->code[prevpos];
-  lua_assert(*previous==previous_instruction(fs));  /* no jump allowed here */
-  if (!ISJUMP(GET_OPCODE(*previous)))
-    prevpos = luaK_code1(fs, jump, NO_JUMP);
-  else {  /* last instruction is already a jump */
-    if (invert)
-      SET_OPCODE(*previous, invertjump(GET_OPCODE(*previous)));
+  e->u.i.info = reg;
+  e->k = VNONRELOC;
+}
+
+
+static void discharge2anyreg (FuncState *fs, expdesc *e) {
+  if (e->k != VNONRELOC) {
+    luaK_reserveregs(fs, 1);
+    discharge2reg(fs, e, fs->freereg-1);
   }
-  luaK_concat(fs, exitlist, prevpos);  /* insert last jump in `exitlist' */
-  luaK_patchlist(fs, *golist, luaK_getlabel(fs));
-  *golist = NO_JUMP;
 }
 
 
-void luaK_goiftrue (FuncState *fs, expdesc *v, int keepvalue) {
-  luaK_testgo(fs, v, 1, keepvalue ? OP_JMPONF : OP_JMPF);
+static void luaK_exp2reg (FuncState *fs, expdesc *e, int reg) {
+  discharge2reg(fs, e, reg);
+  switch (e->k) {
+    case VVOID: {
+      return;  /* nothing to do... */
+    }
+    case VNONRELOC: {
+      if (reg != e->u.i.info)
+        luaK_codeABC(fs, OP_MOVE, reg, e->u.i.info, 0);
+      break;
+    }
+    case VJMP: {
+      luaK_concat(fs, &e->t, e->u.i.info);  /* put this jump in `t' list */
+      break;
+    }
+    default: {
+      lua_assert(0);  /* cannot happen */
+      break;
+    }
+  }
+  dischargejumps(fs, e, reg);
+  e->u.i.info = reg;
+  e->k = VNONRELOC;
 }
 
 
-static void luaK_goiffalse (FuncState *fs, expdesc *v) {
-  luaK_testgo(fs, v, 0, OP_JMPONT);
+void luaK_exp2nextreg (FuncState *fs, expdesc *e) {
+  int reg;
+  dischargevars(fs, e);
+  freeexp(fs, e);
+  reg = fs->freereg;
+  luaK_reserveregs(fs, 1);
+  luaK_exp2reg(fs, e, reg);
 }
 
 
-static int code_label (FuncState *fs, OpCode op, int arg) {
-  luaK_getlabel(fs);  /* those instructions may be jump targets */
-  return luaK_code1(fs, op, arg);
-}
-
-
-void luaK_tostack (LexState *ls, expdesc *v, int onlyone) {
-  FuncState *fs = ls->fs;
-  if (!discharge(fs, v)) {  /* `v' is an expression? */
-    OpCode previous = GET_OPCODE(fs->f->code[fs->pc-1]);
-    if (!ISJUMP(previous) && v->u.l.f == NO_JUMP && v->u.l.t == NO_JUMP) {
-      /* expression has no jumps */
-      if (onlyone)
-        luaK_setcallreturns(fs, 1);  /* call must return 1 value */
-    }
-    else {  /* expression has jumps */
-      int final;  /* position after whole expression */
-      int j = NO_JUMP;  /*  eventual  jump over values */
-      int p_nil = NO_JUMP;  /* position of an eventual PUSHNIL */
-      int p_1 = NO_JUMP;  /* position of an eventual PUSHINT */
-      if (ISJUMP(previous) || need_value(fs, v->u.l.f, OP_JMPONF)
-                           || need_value(fs, v->u.l.t, OP_JMPONT)) {
-        /* expression needs values */
-        if (ISJUMP(previous))
-          luaK_concat(fs, &v->u.l.t, fs->pc-1);  /* put `previous' in t. list */
-        else {
-          j = code_label(fs, OP_JMP, NO_JUMP);  /* to jump over both pushes */
-          /* correct stack for compiler and symbolic execution */
-          luaK_adjuststack(fs, 1);
-        }
-        p_nil = code_label(fs, OP_PUSHNILJMP, 0);
-        p_1 = code_label(fs, OP_PUSHINT, 1);
-        luaK_patchlist(fs, j, luaK_getlabel(fs));
-      }
-      final = luaK_getlabel(fs);
-      luaK_patchlistaux(fs, v->u.l.f, p_nil, OP_JMPONF, final);
-      luaK_patchlistaux(fs, v->u.l.t, p_1, OP_JMPONT, final);
-      v->u.l.f = v->u.l.t = NO_JUMP;
+int luaK_exp2anyreg (FuncState *fs, expdesc *e) {
+  dischargevars(fs, e);
+  if (e->k == VNONRELOC) {
+    if (!hasjumps(e)) return e->u.i.info;  /* exp is already in a register */ 
+    if (e->u.i.info >= fs->nactloc) {  /* reg. is not a local? */
+      dischargejumps(fs, e, e->u.i.info);  /* put value on it */
+      return e->u.i.info;
     }
   }
+  luaK_exp2nextreg(fs, e);  /* default */
+  return e->u.i.info;
 }
 
 
-void luaK_prefix (LexState *ls, UnOpr op, expdesc *v) {
-  FuncState *fs = ls->fs;
-  if (op == OPR_MINUS) {
-    luaK_tostack(ls, v, 1);
-    luaK_code0(fs, OP_MINUS);
-  }
-  else {  /* op == NOT */
-    Instruction *previous;
-    discharge1(fs, v);
-    previous = &fs->f->code[fs->pc-1];
-    if (ISJUMP(GET_OPCODE(*previous)))
-      SET_OPCODE(*previous, invertjump(GET_OPCODE(*previous)));
-    else
-      luaK_code0(fs, OP_NOT);
-    /* interchange true and false lists */
-    { int temp = v->u.l.f; v->u.l.f = v->u.l.t; v->u.l.t = temp; }
-  }
+void luaK_exp2val (FuncState *fs, expdesc *e) {
+  if (hasjumps(e))
+    luaK_exp2anyreg(fs, e);
+  else
+    dischargevars(fs, e);
 }
 
 
-void luaK_infix (LexState *ls, BinOpr op, expdesc *v) {
-  FuncState *fs = ls->fs;
-  switch (op) {
-    case OPR_AND:
-      luaK_goiftrue(fs, v, 1);
-      break;
-    case OPR_OR:
-      luaK_goiffalse(fs, v);
-      break;
-    default:
-      luaK_tostack(ls, v, 1);  /* all other binary operators need a value */
+int luaK_exp2RK (FuncState *fs, expdesc *e) {
+  luaK_exp2val(fs, e);
+  if (e->k == VNUMBER && fs->nk + MAXSTACK <= MAXARG_C) {
+      e->u.i.info = number_constant(fs, e->u.n);
+      e->k = VK;
   }
+  else if (!(e->k == VK && e->u.i.info + MAXSTACK <= MAXARG_C))
+    luaK_exp2anyreg(fs, e);  /* not a constant in the right range */
+  return (e->k == VK) ? e->u.i.info+MAXSTACK : e->u.i.info;
 }
 
 
-
-static const struct {
-  OpCode opcode;  /* opcode for each binary operator */
-  int arg;        /* default argument for the opcode */
-} codes[] = {  /* ORDER OPR */
-      {OP_ADD, 0}, {OP_SUB, 0}, {OP_MULT, 0}, {OP_DIV, 0},
-      {OP_POW, 0}, {OP_CONCAT, 2},
-      {OP_JMPNE, NO_JUMP}, {OP_JMPEQ, NO_JUMP},
-      {OP_JMPLT, NO_JUMP}, {OP_JMPLE, NO_JUMP},
-      {OP_JMPGT, NO_JUMP}, {OP_JMPGE, NO_JUMP}
-};
-
-
-void luaK_posfix (LexState *ls, BinOpr op, expdesc *v1, expdesc *v2) {
-  FuncState *fs = ls->fs;
-  switch (op) {
-    case OPR_AND: {
-      lua_assert(v1->u.l.t == NO_JUMP);  /* list must be closed */
-      discharge1(fs, v2);
-      v1->u.l.t = v2->u.l.t;
-      luaK_concat(fs, &v1->u.l.f, v2->u.l.f);
+void luaK_storevar (FuncState *fs, expdesc *var, expdesc *exp) {
+  switch (var->k) {
+    case VLOCAL: {
+      freeexp(fs, exp);
+      luaK_exp2reg(fs, exp, var->u.i.info);
       break;
     }
-    case OPR_OR: {
-      lua_assert(v1->u.l.f == NO_JUMP);  /* list must be closed */
-      discharge1(fs, v2);
-      v1->u.l.f = v2->u.l.f;
-      luaK_concat(fs, &v1->u.l.t, v2->u.l.t);
+    case VGLOBAL: {
+      int e = luaK_exp2anyreg(fs, exp);
+      freereg(fs, e);
+      luaK_codeABc(fs, OP_SETGLOBAL, e, var->u.i.info);
+      break;
+    }
+    case VINDEXED: {
+      int e = luaK_exp2anyreg(fs, exp);
+      freereg(fs, e);
+      luaK_codeABC(fs, OP_SETTABLE, e, var->u.i.info, var->u.i.aux);
       break;
     }
     default: {
-      luaK_tostack(ls, v2, 1);  /* `v2' must be a value */
-      luaK_code1(fs, codes[op].opcode, codes[op].arg);
+      lua_assert(0);  /* invalid var kind to store */
+      break;
     }
   }
 }
 
 
-static void codelineinfo (FuncState *fs) {
-  Proto *f = fs->f;
-  LexState *ls = fs->ls;
-  if (ls->lastline > fs->lastline) {
-    if (ls->lastline > fs->lastline+1) {
-      luaM_growvector(fs->L, f->lineinfo, fs->nlineinfo, f->sizelineinfo, int,
-                      MAX_INT, l_s("line info overflow"));
-      f->lineinfo[fs->nlineinfo++] = -(ls->lastline - (fs->lastline+1));
-    }
-    luaM_growvector(fs->L, f->lineinfo, fs->nlineinfo, f->sizelineinfo, int,
-                    MAX_INT, l_s("line info overflow"));
-    f->lineinfo[fs->nlineinfo++] = fs->pc;
-    fs->lastline = ls->lastline;
+void luaK_self (FuncState *fs, expdesc *e, expdesc *key) {
+  luaK_exp2anyreg(fs, e);
+  freeexp(fs, e);
+  luaK_reserveregs(fs, 2);
+  luaK_codeABC(fs, OP_SELF, fs->freereg-2, e->u.i.info, luaK_exp2RK(fs, key));
+  e->u.i.info = fs->freereg-2;
+  e->k = VNONRELOC;
+}
+
+
+static OpCode invertoperator (OpCode op) {
+  switch (op) {
+    case OP_TESTNE: return OP_TESTEQ;
+    case OP_TESTEQ: return OP_TESTNE;
+    case OP_TESTLT: return OP_TESTGE;
+    case OP_TESTLE: return OP_TESTGT;
+    case OP_TESTGT: return OP_TESTLE;
+    case OP_TESTGE: return OP_TESTLT;
+    case OP_TESTT: return OP_TESTF;
+    case OP_TESTF: return OP_TESTT;
+    default: lua_assert(0); return op;  /* invalid jump instruction */
   }
 }
 
 
-int luaK_code0 (FuncState *fs, OpCode o) {
-  return luaK_code2(fs, o, 0, 0);
+static void invertjump (FuncState *fs, expdesc *e) {
+  Instruction *pc = getjumpcontrol(fs, e->u.i.info);
+  *pc = SET_OPCODE(*pc, invertoperator(GET_OPCODE(*pc)));
 }
 
 
-int luaK_code1 (FuncState *fs, OpCode o, int arg1) {
-  return luaK_code2(fs, o, arg1, 0);
+static int jumponcond (FuncState *fs, expdesc *e, OpCode op) {
+  if (e->k == VRELOCABLE) {
+    Instruction ie = getcode(fs, e);
+    if (GET_OPCODE(ie) == OP_NOT) {
+      op = invertoperator(op);
+      fs->pc--;  /* remove previous OP_NOT */
+      return luaK_condjump(fs, op, GETARG_B(ie), 0);
+    }
+    /* else go through */
+  }
+  discharge2anyreg(fs, e);
+  freeexp(fs, e);
+  return luaK_condjump(fs, op, e->u.i.info, 0);
 }
 
 
-int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) {
-  Proto *f;
-  Instruction i = previous_instruction(fs);
-  int push = (int)luaK_opproperties[o].push;
-  int pop = (int)luaK_opproperties[o].pop;
-  int optm = 0;  /* 1 when there is an optimization */
-  switch (o) {
-    case OP_CLOSURE: {
-      pop = arg2;
+void luaK_goiftrue (FuncState *fs, expdesc *e) {
+  int pc;  /* pc of last jump */
+  dischargevars(fs, e);
+  switch (e->k) {
+    case VK: case VNUMBER: {
+      pc = NO_JUMP;  /* always true; do nothing */
       break;
     }
-    case OP_SETTABLE: {
-      pop = arg2;
+    case VNIL: {
+      pc = luaK_codeAsBc(fs, OP_JMP, 0, NO_JUMP);  /* always jump */
       break;
     }
-    case OP_SETLIST: {
-      pop = fs->stacklevel - 1 - arg2;
+    case VJMP: {
+      invertjump(fs, e);
+      pc = e->u.i.info;
       break;
     }
-    case OP_SETMAP: {
-      pop = fs->stacklevel - 1 - arg1;
+    case VRELOCABLE:
+    case VNONRELOC: {
+      pc = jumponcond(fs, e, OP_TESTF);
       break;
     }
-    case OP_PUSHNIL: {
-      if (arg1 == 0) return NO_JUMP;  /* nothing to do */
-      push = arg1;
-      switch(GET_OPCODE(i)) {
-        case OP_PUSHNIL: SETARG_U(i, GETARG_U(i)+arg1); optm = 1; break;
-        default: break;
-      }
+    default: {
+      pc = 0;  /* to avoid warnings */
+      lua_assert(0);  /* cannot happen */
       break;
     }
-    case OP_POP: {
-      if (arg1 == 0) return NO_JUMP;  /* nothing to do */
-      pop = arg1;
-      switch(GET_OPCODE(i)) {
-        case OP_SETTABLE: SETARG_B(i, GETARG_B(i)+arg1); optm = 1; break;
-        default: break;
-      }
+  }
+  luaK_concat(fs, &e->f, pc);  /* insert last jump in `f' list */
+  luaK_patchlist(fs, e->t, luaK_getlabel(fs));
+  e->t = NO_JUMP;
+}
+
+
+static void luaK_goiffalse (FuncState *fs, expdesc *e) {
+  int pc;  /* pc of last jump */
+  dischargevars(fs, e);
+  switch (e->k) {
+    case VNIL: {
+      pc = NO_JUMP;  /* always false; do nothing */
       break;
     }
-    case OP_GETTABLE: {
-      switch(GET_OPCODE(i)) {
-        case OP_PUSHSTRING:  /* `t.x' */
-          SET_OPCODE(i, OP_GETDOTTED);
-          optm = 1;
-          break;
-        case OP_GETLOCAL:  /* `t[i]' */
-          SET_OPCODE(i, OP_GETINDEXED);
-          optm = 1;
-          break;
-        default: break;
-      }
+    case VJMP: {
+      pc = e->u.i.info;
       break;
     }
-    case OP_ADD: {
-      switch(GET_OPCODE(i)) {
-        case OP_PUSHINT: SET_OPCODE(i, OP_ADDI); optm = 1; break;  /* `a+k' */
-        default: break;
-      }
+    case VK: case VNUMBER:  /* cannot optimize it (`or' must keep value) */
+    case VRELOCABLE:
+    case VNONRELOC: {
+      pc = jumponcond(fs, e, OP_TESTT);
       break;
     }
-    case OP_SUB: {
-      switch(GET_OPCODE(i)) {
-        case OP_PUSHINT:  /* `a-k' */
-          i = CREATE_S(OP_ADDI, -GETARG_S(i));
-          optm = 1;
-          break;
-        default: break;
-      }
+    default: {
+      pc = 0;  /* to avoid warnings */
+      lua_assert(0);  /* cannot happen */
       break;
     }
-    case OP_CONCAT: {
-      pop = arg1;
-      switch(GET_OPCODE(i)) {
-        case OP_CONCAT:  /* `a..b..c' */
-          SETARG_U(i, GETARG_U(i)+1);
-          optm = 1;
-          break;
-        default: break;
-      }
+  }
+  luaK_concat(fs, &e->t, pc);  /* insert last jump in `t' list */
+  luaK_patchlist(fs, e->f, luaK_getlabel(fs));
+  e->f = NO_JUMP;
+}
+
+
+static void codenot (FuncState *fs, expdesc *e) {
+  dischargevars(fs, e);
+  switch (e->k) {
+    case VNIL: {
+      e->u.n = 1;
+      e->k = VNUMBER;
       break;
     }
-    case OP_MINUS: {
-      switch(GET_OPCODE(i)) {
-        case OP_PUSHINT:  /* `-k' */
-          SETARG_S(i, -GETARG_S(i));
-          optm = 1;
-          break;
-        case OP_PUSHNUM:  /* `-k' */
-          SET_OPCODE(i, OP_PUSHNEGNUM);
-          optm = 1;
-          break;
-        default: break;
-      }
+    case VK:  case VNUMBER: {
+      e->k = VNIL;
       break;
     }
-    case OP_JMPNE: {
-      if (i == CREATE_U(OP_PUSHNIL, 1)) {  /* `a~=nil' */
-        i = CREATE_S(OP_JMPT, NO_JUMP);
-        optm = 1;
-      }
+    case VJMP: {
+      invertjump(fs, e);
       break;
     }
-    case OP_JMPEQ: {
-      if (i == CREATE_U(OP_PUSHNIL, 1)) {  /* `a==nil' */
-        i = CREATE_0(OP_NOT);
-        pop = 1;  /* just undo effect of previous PUSHNIL */
-        optm = 1;
-      }
+    case VRELOCABLE:
+    case VNONRELOC: {
+      discharge2anyreg(fs, e);
+      freeexp(fs, e);
+      e->u.i.info = luaK_codeABC(fs, OP_NOT, 0, e->u.i.info, 0);
+      e->k = VRELOCABLE;
       break;
     }
-    case OP_JMPT:
-    case OP_JMPONT: {
-      switch (GET_OPCODE(i)) {
-        case OP_NOT: {
-          i = CREATE_S(OP_JMPF, NO_JUMP);
-          optm = 1;
-          break;
-        }
-        case OP_PUSHINT: {
-          if (o == OP_JMPT) {  /* JMPONT must keep original integer value */
-            i = CREATE_S(OP_JMP, NO_JUMP);
-            optm = 1;
-          }
-          break;
-        }
-        case OP_PUSHNIL: {
-          if (GETARG_U(i) == 1) {
-            fs->pc--;  /* erase previous instruction */
-            luaK_deltastack(fs, -1);  /* correct stack */
-            return NO_JUMP; 
-          }
-          break;
-        }
-        default: break;
-      }
+    default: {
+      lua_assert(0);  /* cannot happen */
       break;
     }
-    case OP_JMPF:
-    case OP_JMPONF: {
-      switch (GET_OPCODE(i)) {
-        case OP_NOT: {
-          i = CREATE_S(OP_JMPT, NO_JUMP);
-          optm = 1;
-          break;
-        }
-        case OP_PUSHINT: {  /* `while 1 do ...' */
-          fs->pc--;  /* erase previous instruction */
-          luaK_deltastack(fs, -1);  /* correct stack */
-          return NO_JUMP; 
-        }
-        case OP_PUSHNIL: {  /* `repeat ... until nil' */
-          if (GETARG_U(i) == 1) {
-            i = CREATE_S(OP_JMP, NO_JUMP);
-            optm = 1;
-          }
-          break;
-        }
-        default: break;
-      }
+  }
+  /* interchange true and false lists */
+  { int temp = e->f; e->f = e->t; e->t = temp; }
+}
+
+
+void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
+  t->u.i.aux = luaK_exp2RK(fs, k);
+  t->k = VINDEXED;
+}
+
+
+void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) {
+  if (op == OPR_MINUS) {
+    luaK_exp2val(fs, e);
+    if (e->k == VNUMBER)
+      e->u.n = -e->u.n;
+    else {
+      luaK_exp2anyreg(fs, e);
+      freeexp(fs, e);
+      e->u.i.info = luaK_codeABC(fs, OP_UNM, 0, e->u.i.info, 0);
+      e->k = VRELOCABLE;
+    }
+  }
+  else  /* op == NOT */
+    codenot(fs, e);
+}
+
+
+void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
+  switch (op) {
+    case OPR_AND: {
+      luaK_goiftrue(fs, v);
+      break;
+    }
+    case OPR_OR: {
+      luaK_goiffalse(fs, v);
+      break;
+    }
+    case OPR_CONCAT: {
+      luaK_exp2nextreg(fs, v);  /* operand must be on the `stack' */
       break;
     }
-    case OP_GETDOTTED:
-    case OP_GETINDEXED:
-    case OP_ADDI: {
-      lua_assert(0);  /* instruction used only for optimizations */
+    case OPR_SUB: case OPR_DIV: case OPR_POW: {
+      /* non-comutative operators */
+      luaK_exp2anyreg(fs, v);  /* first operand must be a register */
       break;
     }
     default: {
+      luaK_exp2RK(fs, v);
       break;
     }
   }
-  f = fs->f;
-  lua_assert(push != VD);
-  lua_assert(pop != VD);
-  luaK_deltastack(fs, push);
-  luaK_deltastack(fs, -pop);
-  if (optm) {  /* optimize: put instruction in place of last one */
-      f->code[fs->pc-1] = i;  /* change previous instruction */
-      return fs->pc-1;  /* do not generate new instruction */
+}
+
+
+
+/* opcode for each binary operator */
+static const OpCode codes[] = {  /* ORDER OPR */
+  OP_ADD, OP_SUB, OP_MUL, OP_DIV,
+  OP_POW, OP_CONCAT,
+  OP_TESTNE, OP_TESTEQ,
+  OP_TESTLT, OP_TESTLE, OP_TESTGT, OP_TESTGE
+};
+
+
+/* `inverted' opcode for each binary operator */
+/* ( -1 means operator has no inverse) */
+static const OpCode invcodes[] = {  /* ORDER OPR */
+  OP_ADD, (OpCode)-1, OP_MUL, (OpCode)-1,
+  (OpCode)-1, (OpCode)-1,
+  OP_TESTNE, OP_TESTEQ,
+  OP_TESTGT, OP_TESTGE, OP_TESTLT, OP_TESTLE
+};
+
+
+void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) {
+  switch (op) {
+    case OPR_AND: {
+      lua_assert(e1->t == NO_JUMP);  /* list must be closed */
+      dischargevars(fs, e2);
+      luaK_concat(fs, &e1->f, e2->f);
+      e1->k = e2->k; e1->u = e2->u; e1->t = e2->t;
+      break;
+    }
+    case OPR_OR: {
+      lua_assert(e1->f == NO_JUMP);  /* list must be closed */
+      dischargevars(fs, e2);
+      luaK_concat(fs, &e1->t, e2->t);
+      e1->k = e2->k; e1->u = e2->u; e1->f = e2->f;
+      break;
+    }
+    case OPR_CONCAT: {
+      luaK_exp2val(fs, e2);
+      if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) {
+        lua_assert(e1->u.i.info == GETARG_B(getcode(fs, e2))-1);
+        freeexp(fs, e1);
+        SETARG_B(getcode(fs, e2), e1->u.i.info);
+        e1->k = e2->k; e1->u.i.info = e2->u.i.info;
+      }
+      else {
+        luaK_exp2nextreg(fs, e2);
+        freeexp(fs, e2);
+        freeexp(fs, e1);
+        e1->u.i.info = luaK_codeABC(fs, codes[op], 0, e1->u.i.info,
+                                                      e2->u.i.info);
+        e1->k = VRELOCABLE;
+      }
+      break;
+    }
+    case OPR_EQ: case OPR_NE: {
+      luaK_exp2val(fs, e2);
+      if (e2->k == VNIL) {  /* exp x= nil ? */
+        if (e1->k == VK) {  /* constant x= nil ? */
+          if (op == OPR_EQ)  /* constant == nil ? */
+            e1->k = VNIL;  /* always false */
+          /* else always true (leave the constant itself) */
+        }
+        else {
+          OpCode opc = (op == OPR_EQ) ? OP_TESTF : OP_TESTT;
+          e1->u.i.info = jumponcond(fs, e1, opc);
+          e1->k = VJMP;
+        }
+        break;
+      }
+      /* else go through */
+    }
+    default: {
+      int o1, o2;
+      OpCode opc;
+      if (e1->k != VK) {  /* not a constant operator? */
+        o1 = e1->u.i.info;
+        o2 = luaK_exp2RK(fs, e2);  /* maybe other operator is constant... */
+        opc = codes[op];
+      }
+      else {  /* invert operands */
+        o2 = luaK_exp2RK(fs, e1);  /* constant must be 2nd operand */
+        o1 = luaK_exp2anyreg(fs, e2);  /* other operator must be in register */
+        opc = invcodes[op];  /* use inverted operator */
+      }
+      freeexp(fs, e2);
+      freeexp(fs, e1);
+      if (op < OPR_NE) {  /* ORDER OPR */
+        e1->u.i.info = luaK_codeABC(fs, opc, 0, o1, o2);
+        e1->k = VRELOCABLE;
+      }
+      else {  /* jump */
+        e1->u.i.info = luaK_condjump(fs, opc, o1, o2);
+        e1->k = VJMP;
+      }
+    }
   }
-  /* else build new instruction */
-  switch ((enum Mode)luaK_opproperties[o].mode) {
-    case iO: i = CREATE_0(o); break;
-    case iU: i = CREATE_U(o, arg1); break;
-    case iS: i = CREATE_S(o, arg1); break;
-    case iAB: i = CREATE_AB(o, arg1, arg2); break;
+}
+
+
+static void codelineinfo (FuncState *fs) {
+  Proto *f = fs->f;
+  LexState *ls = fs->ls;
+  if (ls->lastline > fs->lastline) {
+    if (ls->lastline > fs->lastline+1) {
+      luaM_growvector(fs->L, f->lineinfo, fs->nlineinfo, f->sizelineinfo, int,
+                      MAX_INT, l_s("line info overflow"));
+      f->lineinfo[fs->nlineinfo++] = -(ls->lastline - (fs->lastline+1));
+    }
+    luaM_growvector(fs->L, f->lineinfo, fs->nlineinfo, f->sizelineinfo, int,
+                    MAX_INT, l_s("line info overflow"));
+    f->lineinfo[fs->nlineinfo++] = fs->pc;
+    fs->lastline = ls->lastline;
   }
+}
+
+
+static int luaK_code (FuncState *fs, Instruction i) {
+  Proto *f;
   codelineinfo(fs);
+  f = fs->f;
   /* put new instruction in code array */
   luaM_growvector(fs->L, f->code, fs->pc, f->sizecode, Instruction,
                   MAX_INT, l_s("code size overflow"));
   f->code[fs->pc] = i;
+/*printf("free: %d  ", fs->freereg); printopcode(f, fs->pc);*/
   return fs->pc++;
 }
 
 
-const OpProperties luaK_opproperties[] = {
-  {iU, 0, 0},	/* OP_RETURN */
-  {iAB, 0, 0},	/* OP_CALL */
-  {iU, VD, 0},	/* OP_PUSHNIL */
-  {iU, 0, VD},	/* OP_POP */
-  {iS, 1, 0},	/* OP_PUSHINT */
-  {iU, 1, 0},	/* OP_PUSHSTRING */
-  {iU, 1, 0},	/* OP_PUSHNUM */
-  {iU, 1, 0},	/* OP_PUSHNEGNUM */
-  {iU, 1, 0},	/* OP_PUSHUPVALUE */
-  {iU, 1, 0},	/* OP_GETLOCAL */
-  {iU, 1, 0},	/* OP_GETGLOBAL */
-  {iO, 1, 2},	/* OP_GETTABLE */
-  {iU, 1, 1},	/* OP_GETDOTTED */
-  {iU, 1, 1},	/* OP_GETINDEXED */
-  {iU, 2, 1},	/* OP_PUSHSELF */
-  {iU, 1, 0},	/* OP_CREATETABLE */
-  {iU, 0, 1},	/* OP_SETLOCAL */
-  {iU, 0, 1},	/* OP_SETGLOBAL */
-  {iAB, 0, VD},	/* OP_SETTABLE */
-  {iAB, 0, VD},	/* OP_SETLIST */
-  {iU, 0, VD},	/* OP_SETMAP */
-  {iO, 1, 2},	/* OP_ADD */
-  {iS, 1, 1},	/* OP_ADDI */
-  {iO, 1, 2},	/* OP_SUB */
-  {iO, 1, 2},	/* OP_MULT */
-  {iO, 1, 2},	/* OP_DIV */
-  {iO, 1, 2},	/* OP_POW */
-  {iU, 1, VD},	/* OP_CONCAT */
-  {iO, 1, 1},	/* OP_MINUS */
-  {iO, 1, 1},	/* OP_NOT */
-  {iS, 0, 2},	/* OP_JMPNE */
-  {iS, 0, 2},	/* OP_JMPEQ */
-  {iS, 0, 2},	/* OP_JMPLT */
-  {iS, 0, 2},	/* OP_JMPLE */
-  {iS, 0, 2},	/* OP_JMPGT */
-  {iS, 0, 2},	/* OP_JMPGE */
-  {iS, 0, 1},	/* OP_JMPT */
-  {iS, 0, 1},	/* OP_JMPF */
-  {iS, 0, 1},	/* OP_JMPONT */
-  {iS, 0, 1},	/* OP_JMPONF */
-  {iS, 0, 0},	/* OP_JMP */
-  {iO, 0, 0},	/* OP_PUSHNILJMP */
-  {iS, 0, 0},	/* OP_FORPREP */
-  {iS, 0, 3},	/* OP_FORLOOP */
-  {iS, 3, 0},	/* OP_LFORPREP */
-  {iS, 0, 4},	/* OP_LFORLOOP */
-  {iAB, 1, VD}	/* OP_CLOSURE */
-};
+int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) {
+  lua_assert(getOpMode(o) == iABC);
+  return luaK_code(fs, CREATE_ABC(o, a, b, c));
+}
+
+
+int luaK_codeABc (FuncState *fs, OpCode o, int a, int bc) {
+  lua_assert(getOpMode(o) == iABc || getOpMode(o) == iAsBc);
+  return luaK_code(fs, CREATE_ABc(o, a, bc));
+}
 

+ 21 - 28
lcode.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lcode.h,v 1.20 2001/02/20 18:15:33 roberto Exp roberto $
+** $Id: lcode.h,v 1.21 2001/02/23 17:17:25 roberto Exp roberto $
 ** Code generator for Lua
 ** See Copyright Notice in lua.h
 */
@@ -31,43 +31,36 @@ typedef enum BinOpr {
   OPR_NOBINOPR
 } BinOpr;
 
-typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_NOUNOPR } UnOpr;
-
-
-enum Mode {iO, iU, iS, iAB};  /* instruction format */
+#define binopistest(op)	((op) >= OPR_NE)
 
-#define VD	100	/* flag for variable delta */
-
-typedef struct OpProperties {
-  lu_byte mode;
-  lu_byte push;
-  lu_byte pop;
-} OpProperties;
+typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_NOUNOPR } UnOpr;
 
-extern const OpProperties luaK_opproperties[];
 
+#define luaK_codeAsBc(fs,o,A,sBc)	luaK_codeABc(fs,o,A,(sBc)+MAXARG_sBc)
 
 void luaK_error (LexState *ls, const l_char *msg);
-int luaK_code0 (FuncState *fs, OpCode o);
-int luaK_code1 (FuncState *fs, OpCode o, int arg1);
-int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2);
+int luaK_codeABc (FuncState *fs, OpCode o, int A, int Bc);
+int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C);
+void luaK_nil (FuncState *fs, int from, int n);
+void luaK_reserveregs (FuncState *fs, int n);
+int luaK_stringk (FuncState *fs, TString *s);
+int luaK_exp2anyreg (FuncState *fs, expdesc *e);
+void luaK_exp2nextreg (FuncState *fs, expdesc *e);
+void luaK_exp2val (FuncState *fs, expdesc *e);
+int luaK_exp2RK (FuncState *fs, expdesc *e);
+void luaK_self (FuncState *fs, expdesc *e, expdesc *key);
+void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k);
+void luaK_goiftrue (FuncState *fs, expdesc *e);
+void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e);
+void luaK_setcallreturns (FuncState *fs, expdesc *var, int nresults);
 int luaK_jump (FuncState *fs);
 void luaK_patchlist (FuncState *fs, int list, int target);
 void luaK_fixfor (FuncState *fs, int pc, int dest);
 void luaK_concat (FuncState *fs, int *l1, int l2);
-void luaK_goiftrue (FuncState *fs, expdesc *v, int keepvalue);
 int luaK_getlabel (FuncState *fs);
-void luaK_deltastack (FuncState *fs, int delta);
-void luaK_kstr (LexState *ls, int c);
-void luaK_number (FuncState *fs, lua_Number f);
-void luaK_adjuststack (FuncState *fs, int n);
-int luaK_lastisopen (FuncState *fs);
-void luaK_setcallreturns (FuncState *fs, int nresults);
-void luaK_tostack (LexState *ls, expdesc *v, int onlyone);
-void luaK_storevar (LexState *ls, const expdesc *var);
-void luaK_prefix (LexState *ls, UnOpr op, expdesc *v);
-void luaK_infix (LexState *ls, BinOpr op, expdesc *v);
-void luaK_posfix (LexState *ls, BinOpr op, expdesc *v1, expdesc *v2);
+void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v);
+void luaK_infix (FuncState *fs, BinOpr op, expdesc *v);
+void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, expdesc *v2);
 
 
 #endif

+ 195 - 165
ldebug.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ldebug.c,v 1.75 2001/03/26 14:31:49 roberto Exp roberto $
+** $Id: ldebug.c,v 1.76 2001/04/06 18:25:00 roberto Exp roberto $
 ** Debug Interface
 ** See Copyright Notice in lua.h
 */
@@ -22,6 +22,7 @@
 #include "ltable.h"
 #include "ltm.h"
 #include "luadebug.h"
+#include "lvm.h"
 
 
 
@@ -298,6 +299,10 @@ LUA_API int lua_getinfo (lua_State *L, const l_char *what, lua_Debug *ar) {
 
 #define check(x)		if (!(x)) return 0;
 
+#define checkjump(pt,pc)	check(0 <= pc && pc < pt->sizecode)
+
+#define checkreg(pt,reg)	check((reg) < (pt)->maxstacksize)
+
 
 static int checklineinfo (const Proto *pt) {
   int *lineinfo = pt->lineinfo;
@@ -318,231 +323,199 @@ static int precheck (const Proto *pt) {
 }
 
 
-/* value for non-initialized entries in array stacklevel */
-#define SL_EMPTY	255
-
-#define checkjump(pt,sl,top,pc)	if (!checkjump_aux(pt,sl,top,pc)) return 0;
-
-static int checkjump_aux (const Proto *pt, lu_byte *sl, int top, int pc) {
-  check(0 <= pc && pc < pt->sizecode);
-  if (sl == NULL) return 1;  /* not full checking */
-  if (sl[pc] == SL_EMPTY)
-    sl[pc] = (lu_byte)top;
-  else
-    check(sl[pc] == top);
-  return 1;
+static int checkopenop (Instruction i) {
+  OpCode op = GET_OPCODE(i);
+  switch (op) {
+    case OP_CALL:
+    case OP_RETURN: {
+      check(GETARG_B(i) == NO_REG);
+      return 1;
+    }
+    case OP_SETLISTO: return 1;
+    default: return 0;  /* invalid instruction after an open call */
+  }
 }
 
 
-static Instruction luaG_symbexec (lua_State *L, const Proto *pt,
-                                  int lastpc, int stackpos) {
-  int stack[MAXSTACK];  /* stores last instruction that changed a stack entry */
-  lu_byte *sl = NULL;
-  int top;
+static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) {
   int pc;
-  if (stackpos < 0) {  /* full check? */
-    int i;
-    sl = luaO_openspace(L, pt->sizecode, lu_byte);
-    for (i=0; i<pt->sizecode; i++)  /* initialize stack-level array */
-      sl[i] = SL_EMPTY;
+  int last;  /* stores position of last instruction that changed `reg' */
+  last = pt->sizecode-1;  /* points to final return (a `neutral' instruction) */
+  if (reg == NO_REG)  /* full check? */
     check(precheck(pt));
-  }
-  top = pt->numparams;
-  pc = 0;
-  if (pt->is_vararg)  /* varargs? */
-    top++;  /* `arg' */
-  if (sl) sl[0] = (lu_byte)top;
-  while (pc < lastpc) {
-    const Instruction i = pt->code[pc++];
+  for (pc = 0; pc < lastpc; pc++) {
+    const Instruction i = pt->code[pc];
     OpCode op = GET_OPCODE(i);
-    int arg1 = 0;
-    int arg2 = 0;
-    int push, pop;
-    check(op < NUM_OPCODES);
-    push = (int)luaK_opproperties[op].push;
-    pop = (int)luaK_opproperties[op].pop;
-    switch ((enum Mode)luaK_opproperties[op].mode) {
-      case iO: break;
-      case iU: arg1 = GETARG_U(i); check(arg1 >= 0); break;
-      case iS: arg1 = GETARG_S(i); break;
-      case iAB:
-        arg1 = GETARG_A(i); arg2 = GETARG_B(i); check(arg1 >= 0); break;
-    }
-    switch (op) {
-      case OP_RETURN: {
-        check(arg1 <= top);
-        pop = top-arg1;
+    int a = GETARG_A(i);
+    int b = 0;
+    int c = 0;
+#undef check
+#define check(x)		if (!(x)) { \
+printf(">>>%d %d %d %d %d %d\n", op, a, b, c, pt->maxstacksize, pt->sizek); \
+return 0; }
+    switch (getOpMode(op)) {
+      case iABC: {
+        b = GETARG_B(i);
+        c = GETARG_C(i);
+        if (testOpMode(op, OpModeBreg)) {
+          checkreg(pt, b);
+          check(c < pt->maxstacksize ||
+               (c >= MAXSTACK && c-MAXSTACK < pt->sizek));
+        }
         break;
       }
-      case OP_CALL: {
-        if (arg2 == MULT_RET) arg2 = 1;
-        check(arg1 < top);
-        pop = top-arg1;
-        push = arg2;
+      case iABc: {
+        b = GETARG_Bc(i);
+        if (testOpMode(op, OpModeK)) check(b < pt->sizek);
         break;
       }
-      case OP_PUSHNIL: {
-        check(arg1 > 0);
-        push = arg1;
+      case iAsBc: {
+        b = GETARG_sBc(i);
         break;
       }
-      case OP_POP: {
-        pop = arg1;
+    }
+    if (testOpMode(op, OpModeAreg)) checkreg(pt, a);
+    if (testOpMode(op, OpModesetA)) {
+      if (a == reg) last = pc;  /* change register `a' */
+    }
+    if (testOpMode(op, OpModeT))
+      check(GET_OPCODE(pt->code[pc+1]) == OP_CJMP);
+    switch (op) {
+      case OP_LOADNIL: {
+        if (a <= reg && reg <= b)
+          last = pc;  /* set registers from `a' to `b' */
         break;
       }
-      case OP_PUSHSTRING:
-      case OP_GETGLOBAL:
-      case OP_GETDOTTED:
-      case OP_PUSHSELF:
-      case OP_SETGLOBAL: {
-        check(arg1 < pt->sizekstr);
+      case OP_LOADUPVAL: {
+        check(b < pt->nupvalues);
         break;
       }
-      case OP_PUSHNUM:
-      case OP_PUSHNEGNUM: {
-        check(arg1 < pt->sizeknum);
+      case OP_GETGLOBAL:
+      case OP_SETGLOBAL: {
+        check(ttype(&pt->k[b]) == LUA_TSTRING);
         break;
       }
-      case OP_PUSHUPVALUE: {
-        check(arg1 < pt->nupvalues);
+      case OP_SELF: {
+        checkreg(pt, a+1);
+        if (reg == a+1) last = pc;
         break;
       }
-      case OP_GETLOCAL:
-      case OP_GETINDEXED:
-      case OP_SETLOCAL: {
-        check(arg1 < top);
+      case OP_CONCAT: {
+        check(b < c);  /* at least two operands */
         break;
       }
-      case OP_SETTABLE: {
-        check(3 <= arg1 && arg1 <= top);
-        pop = arg2;
+      case OP_JMP:
+      case OP_CJMP: {
+        int dest = pc+1+b;
+	check(0 <= dest && dest < pt->sizecode);
+        /* not full check and jump is forward and do not skip `lastpc'? */
+        if (reg != NO_REG && pc < dest && dest <= lastpc)
+          pc += b;  /* do the jump */
         break;
       }
-      case OP_SETLIST: {
-        check(arg2 >= 0);
-        pop = top-arg2-1;
+      case OP_TESTT:
+      case OP_TESTF: {
+        if (a != NO_REG)
+          checkreg(pt, a);
         break;
       }
-      case OP_SETMAP: {
-        check(arg1 >= 0);
-        pop = top-arg1-1;
+      case OP_NILJMP: {
+        check(pc+2 < pt->sizecode);  /* check its jump */
         break;
       }
-      case OP_CONCAT: {
-        pop = arg1;
+      case OP_CALL: {
+        if (b == NO_REG) b = pt->maxstacksize;
+        if (c == NO_REG) {
+          check(checkopenop(pt->code[pc+1]));
+          c = 1;
+        }
+        check(b > a);
+        checkreg(pt, b-1);
+        checkreg(pt, a+c-1);
+        if (reg >= a) last = pc;  /* affect all registers above base */
         break;
       }
-      case OP_CLOSURE: {
-        check(arg1 < pt->sizekproto);
-        check(arg2 == pt->kproto[arg1]->nupvalues);
-        pop = arg2;
+      case OP_RETURN: {
+        if (b == NO_REG) b = pt->maxstacksize;
+        checkreg(pt, b-1);
         break;
       }
-      case OP_JMPNE:
-      case OP_JMPEQ:
-      case OP_JMPLT:
-      case OP_JMPLE:
-      case OP_JMPGT:
-      case OP_JMPGE:
-      case OP_JMPT:
-      case OP_JMPF:
-      case OP_JMP: {
-        checkjump(pt, sl, top-pop, pc+arg1);
+      case OP_FORPREP:
+      case OP_TFORPREP: {
+        int dest = pc-b;  /* jump is negated here */
+        check(0 <= dest && dest < pt->sizecode &&
+              GET_OPCODE(pt->code[dest]) == op+1);
         break;
       }
       case OP_FORLOOP:
-      case OP_LFORLOOP:
-      case OP_JMPONT:
-      case OP_JMPONF: {
-        int newpc = pc+arg1;
-        checkjump(pt, sl, top, newpc);
-        /* jump is forward and do not skip `lastpc' and not full check? */
-        if (pc < newpc && newpc <= lastpc && stackpos >= 0) {
-          stack[top-1] = pc-1;  /* value comes from `and'/`or' */
-          pc = newpc;  /* do the jump */
-          pop = 0;  /* do not pop */
-        }
-        break;
-      }
-      case OP_PUSHNILJMP: {
-        check(GET_OPCODE(pt->code[pc]) == OP_PUSHINT); /* only valid sequence */
+      case OP_TFORLOOP: {
+        int dest = pc+b;
+        check(0 <= dest && dest < pt->sizecode &&
+              pt->code[dest] == SET_OPCODE(i, op-1));
+        checkreg(pt, a + ((op == OP_FORLOOP) ? 2 : 3));
         break;
       }
-      case OP_FORPREP: {
-        int endfor = pc-arg1-1;  /* jump is `negative' here */
-        check(top >= 3);
-        checkjump(pt, sl, top+push, endfor);
-        check(GET_OPCODE(pt->code[endfor]) == OP_FORLOOP);
-        check(GETARG_S(pt->code[endfor]) == arg1);
-        break;
-      }
-      case OP_LFORPREP: {
-        int endfor = pc-arg1-1;  /* jump is `negative' here */
-        check(top >= 1);
-        checkjump(pt, sl, top+push, endfor);
-        check(GET_OPCODE(pt->code[endfor]) == OP_LFORLOOP);
-        check(GETARG_S(pt->code[endfor]) == arg1);
+      case OP_SETLIST: {
+        checkreg(pt, a + (b&(LFIELDS_PER_FLUSH-1)) + 1);
         break;
       }
-      case OP_PUSHINT:
-      case OP_GETTABLE:
-      case OP_CREATETABLE:
-      case OP_ADD:
-      case OP_ADDI:
-      case OP_SUB:
-      case OP_MULT:
-      case OP_DIV:
-      case OP_POW:
-      case OP_MINUS:
-      case OP_NOT: {
+      case OP_CLOSURE: {
+        check(b < pt->sizekproto);
+        checkreg(pt, a + pt->kproto[b]->nupvalues - 1);
         break;
       }
+      default: break;
     }
-    top -= pop;
-    check(0 <= top && top+push <= pt->maxstacksize);
-    while (push--) stack[top++] = pc-1;
-    checkjump(pt, sl, top, pc);
   }
-  return (stackpos >= 0) ? pt->code[stack[stackpos]] : 1;
+  return pt->code[last];
 }
 
 /* }====================================================== */
 
 
-int luaG_checkcode (lua_State *L, const Proto *pt) {
-  return luaG_symbexec(L, pt, pt->sizecode-1, -1);
+int luaG_checkcode (const Proto *pt) {
+  return luaG_symbexec(pt, pt->sizecode, NO_REG);
 }
 
 
 static const l_char *getobjname (lua_State *L, StkId obj, const l_char **name) {
   CallInfo *ci = ci_stack(L, obj);
-  if (!isLmark(ci))
-    return NULL;  /* not an active Lua function */
-  else {
+  if (isLmark(ci)) {  /* an active Lua function? */
     Proto *p = ci_func(ci)->f.l;
     int pc = currentpc(ci);
     int stackpos = obj - ci->base;
-    Instruction i = luaG_symbexec(L, p, pc, stackpos);
+    Instruction i;
+    *name = luaF_getlocalname(p, stackpos+1, pc);
+    if (*name)  /* is a local? */
+      return l_s("local");
+    i = luaG_symbexec(p, pc, stackpos);  /* try symbolic execution */
     lua_assert(pc != -1);
     switch (GET_OPCODE(i)) {
       case OP_GETGLOBAL: {
-        *name = getstr(p->kstr[GETARG_U(i)]);
+        lua_assert(ttype(&p->k[GETARG_Bc(i)]) == LUA_TSTRING);
+        *name = getstr(tsvalue(&p->k[GETARG_Bc(i)]));
         return l_s("global");
       }
-      case OP_GETLOCAL: {
-        *name = luaF_getlocalname(p, GETARG_U(i)+1, pc);
-        lua_assert(*name);
-        return l_s("local");
+      case OP_MOVE: {
+        int a = GETARG_A(i);
+        int b = GETARG_B(i);  /* move from `b' to `a' */
+        if (b < a)
+          return getobjname(L, ci->base+b, name);  /* get name for `b' */
+        break;
       }
-      case OP_PUSHSELF:
-      case OP_GETDOTTED: {
-        *name = getstr(p->kstr[GETARG_U(i)]);
-        return l_s("field");
+      case OP_GETTABLE:
+      case OP_SELF: {
+        int c = GETARG_C(i) - MAXSTACK;
+        if (c >= 0 && ttype(&p->k[c]) == LUA_TSTRING) {
+          *name = getstr(tsvalue(&p->k[c]));
+          return l_s("field");
+        }
+        break;
       }
-      default:
-        return NULL;  /* no useful name found */
+      default: break;
     }
   }
+  return NULL;  /* no useful name found */
 }
 
 
@@ -576,10 +549,18 @@ void luaG_typeerror (lua_State *L, StkId o, const l_char *op) {
 }
 
 
-void luaG_binerror (lua_State *L, StkId p1, int t, const l_char *op) {
-  if (ttype(p1) == t) p1++;
-  lua_assert(ttype(p1) != t);
-  luaG_typeerror(L, p1, op);
+void luaG_concaterror (lua_State *L, StkId p1, StkId p2) {
+  if (ttype(p1) == LUA_TSTRING) p1 = p2;
+  lua_assert(ttype(p1) != LUA_TSTRING);
+  luaG_typeerror(L, p1, l_s("concat"));
+}
+
+
+void luaG_aritherror (lua_State *L, StkId p1, TObject *p2) {
+  TObject temp;
+  if (luaV_tonumber(p1, &temp) != NULL)
+    p1 = p2;  /* first operand is OK; error is in the second */
+  luaG_typeerror(L, p1, l_s("perform arithmetic on"));
 }
 
 
@@ -592,3 +573,52 @@ void luaG_ordererror (lua_State *L, const TObject *p1, const TObject *p2) {
     luaO_verror(L, l_s("attempt to compare %.10s with %.10s"), t1, t2);
 }
 
+
+
+#define opmode(t,a,b,c,sa,k,m) (((t)<<OpModeT) | \
+   ((a)<<OpModeAreg) | ((b)<<OpModeBreg) | ((c)<<OpModeCreg) | \
+   ((sa)<<OpModesetA) | ((k)<<OpModeK) | (m))
+
+
+const unsigned char luaG_opmodes[] = {
+/*       T A B C sA K mode		   opcode    */
+  opmode(0,1,1,0, 1,0,iABC),		/* OP_MOVE */
+  opmode(0,1,0,0, 1,1,iABc),		/* OP_LOADK */
+  opmode(0,1,0,0, 1,0,iAsBc),		/* OP_LOADINT */
+  opmode(0,1,1,0, 1,0,iABC),		/* OP_LOADNIL */
+  opmode(0,1,0,0, 1,0,iABc),		/* OP_LOADUPVAL */
+  opmode(0,1,0,0, 1,1,iABc),		/* OP_GETGLOBAL */
+  opmode(0,1,1,1, 1,0,iABC),		/* OP_GETTABLE */
+  opmode(0,1,0,0, 0,1,iABc),		/* OP_SETGLOBAL */
+  opmode(0,1,1,1, 0,0,iABC),		/* OP_SETTABLE */
+  opmode(0,1,0,0, 1,0,iABc),		/* OP_NEWTABLE */
+  opmode(0,1,1,1, 1,0,iABC),		/* OP_SELF */
+  opmode(0,1,1,1, 1,0,iABC),		/* OP_ADD */
+  opmode(0,1,1,1, 1,0,iABC),		/* OP_SUB */
+  opmode(0,1,1,1, 1,0,iABC),		/* OP_MUL */
+  opmode(0,1,1,1, 1,0,iABC),		/* OP_DIV */
+  opmode(0,1,1,1, 1,0,iABC),		/* OP_POW */
+  opmode(0,1,1,0, 1,0,iABC),		/* OP_UNM */
+  opmode(0,1,1,0, 1,0,iABC),		/* OP_NOT */
+  opmode(0,1,1,1, 1,0,iABC),		/* OP_CONCAT */
+  opmode(0,0,0,0, 0,0,iAsBc),		/* OP_JMP */
+  opmode(0,0,0,0, 0,0,iAsBc),		/* OP_CJMP */
+  opmode(1,0,1,1, 0,0,iABC),		/* OP_TESTEQ */
+  opmode(1,0,1,1, 0,0,iABC),		/* OP_TESTNE */
+  opmode(1,0,1,1, 0,0,iABC),		/* OP_TESTLT */
+  opmode(1,0,1,1, 0,0,iABC),		/* OP_TESTLE */
+  opmode(1,0,1,1, 0,0,iABC),		/* OP_TESTGT */
+  opmode(1,0,1,1, 0,0,iABC),		/* OP_TESTGE */
+  opmode(1,0,1,0, 1,0,iABC),		/* OP_TESTT */
+  opmode(1,0,1,0, 1,0,iABC),		/* OP_TESTF */
+  opmode(0,1,0,0, 1,0,iAsBc),		/* OP_NILJMP */
+  opmode(0,1,0,0, 0,0,iABC),		/* OP_CALL */
+  opmode(0,1,0,0, 0,0,iABC),		/* OP_RETURN */
+  opmode(0,1,0,0, 0,0,iAsBc),		/* OP_FORPREP */
+  opmode(0,1,0,0, 0,0,iAsBc),		/* OP_FORLOOP */
+  opmode(0,1,0,0, 0,0,iAsBc),		/* OP_TFORPREP */
+  opmode(0,1,0,0, 0,0,iAsBc),		/* OP_TFORLOOP */
+  opmode(0,1,0,0, 0,0,iABc),		/* OP_SETLIST */
+  opmode(0,1,0,0, 0,0,iABc),		/* OP_SETLIST0 */
+  opmode(0,1,0,0, 0,0,iABc)		/* OP_CLOSURE */
+};

+ 24 - 3
ldebug.h

@@ -1,5 +1,5 @@
 /*
-** $Id: ldebug.h,v 1.10 2001/02/12 19:54:50 roberto Exp roberto $
+** $Id: ldebug.h,v 1.11 2001/02/23 17:17:25 roberto Exp roberto $
 ** Auxiliary functions from Debug Interface module
 ** See Copyright Notice in lua.h
 */
@@ -12,11 +12,32 @@
 #include "luadebug.h"
 
 
+enum OpMode {iABC, iABc, iAsBc};  /* basic instruction format */
+
+/*
+** masks for instruction properties
+*/
+enum OpModeMask {
+  OpModeAreg = 2,	/* A is a register */
+  OpModeBreg,		/* B is a register */
+  OpModeCreg,		/* C is a register/constant */
+  OpModesetA,		/* instruction set register A */
+  OpModeK,		/* Bc is a constant */
+  OpModeT		/* operator is a test */
+};
+
+extern const unsigned char luaG_opmodes[];
+
+#define getOpMode(m)		((enum OpMode)(luaG_opmodes[m] & 3))
+#define testOpMode(m, b)	(luaG_opmodes[m] & (1 << (b)))
+
+
 void luaG_typeerror (lua_State *L, StkId o, const l_char *op);
-void luaG_binerror (lua_State *L, StkId p1, int t, const l_char *op);
+void luaG_concaterror (lua_State *L, StkId p1, StkId p2);
+void luaG_aritherror (lua_State *L, StkId p1, TObject *p2);
 int luaG_getline (int *lineinfo, int pc, int refline, int *refi);
 void luaG_ordererror (lua_State *L, const TObject *p1, const TObject *p2);
-int luaG_checkcode (lua_State *L, const Proto *pt);
+int luaG_checkcode (const Proto *pt);
 
 
 #endif

+ 4 - 7
lfunc.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lfunc.c,v 1.42 2001/02/23 17:17:25 roberto Exp roberto $
+** $Id: lfunc.c,v 1.43 2001/03/26 14:31:49 roberto Exp roberto $
 ** Auxiliary functions to manipulate prototypes and closures
 ** See Copyright Notice in lua.h
 */
@@ -30,10 +30,8 @@ Closure *luaF_newclosure (lua_State *L, int nelems) {
 
 Proto *luaF_newproto (lua_State *L) {
   Proto *f = luaM_new(L, Proto);
-  f->knum = NULL;
-  f->sizeknum = 0;
-  f->kstr = NULL;
-  f->sizekstr = 0;
+  f->k = NULL;
+  f->sizek = 0;
   f->kproto = NULL;
   f->sizekproto = 0;
   f->code = NULL;
@@ -58,8 +56,7 @@ Proto *luaF_newproto (lua_State *L) {
 void luaF_freeproto (lua_State *L, Proto *f) {
   luaM_freearray(L, f->code, f->sizecode, Instruction);
   luaM_freearray(L, f->locvars, f->sizelocvars, struct LocVar);
-  luaM_freearray(L, f->kstr, f->sizekstr, TString *);
-  luaM_freearray(L, f->knum, f->sizeknum, lua_Number);
+  luaM_freearray(L, f->k, f->sizek, TObject);
   luaM_freearray(L, f->kproto, f->sizekproto, Proto *);
   luaM_freearray(L, f->lineinfo, f->sizelineinfo, int);
   luaM_freelem(L, f, Proto);

+ 5 - 3
lgc.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lgc.c,v 1.96 2001/04/11 14:42:41 roberto Exp roberto $
+** $Id: lgc.c,v 1.97 2001/04/17 17:35:54 roberto Exp roberto $
 ** Garbage Collector
 ** See Copyright Notice in lua.h
 */
@@ -48,8 +48,10 @@ static void protomark (Proto *f) {
     int i;
     f->marked = 1;
     strmark(f->source);
-    for (i=0; i<f->sizekstr; i++)
-      strmark(f->kstr[i]);
+    for (i=0; i<f->sizek; i++) {
+      if (ttype(f->k+i) == LUA_TSTRING)
+        strmark(tsvalue(f->k+i));
+    }
     for (i=0; i<f->sizekproto; i++)
       protomark(f->kproto[i]);
     for (i=0; i<f->sizelocvars; i++)  /* mark local-variable names */

+ 5 - 84
llimits.h

@@ -1,5 +1,5 @@
 /*
-** $Id: llimits.h,v 1.27 2001/02/23 20:28:56 roberto Exp roberto $
+** $Id: llimits.h,v 1.28 2001/03/26 14:31:49 roberto Exp roberto $
 ** Limits, basic types, and some other `installation-dependent' definitions
 ** See Copyright Notice in lua.h
 */
@@ -89,92 +89,23 @@ union L_Umaxalign { double d; void *s; long l; };
 /*
 ** type for virtual-machine instructions
 ** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h)
-** For a very small machine, you may change that to 2 bytes (and adjust
-** the following limits accordingly)
 */
 typedef unsigned long Instruction;
 
 
-/*
-** size and position of opcode arguments.
-** For an instruction with 2 bytes, size is 16, and size_b can be 5
-** (accordingly, size_u will be 10, and size_a will be 5)
-*/
-#define SIZE_INSTRUCTION        32
-#define SIZE_B          8
-
-#define SIZE_OP         6
-#define SIZE_U          (SIZE_INSTRUCTION-SIZE_OP)
-#define POS_U           SIZE_OP
-#define POS_B           SIZE_OP
-#define SIZE_A          (SIZE_INSTRUCTION-(SIZE_OP+SIZE_B))
-#define POS_A           (SIZE_OP+SIZE_B)
-
-
-/*
-** limits for opcode arguments.
-** we use (signed) int to manipulate most arguments,
-** so they must fit in BITS_INT-1 bits (-1 for sign)
-*/
-#if SIZE_U < BITS_INT-1
-#define MAXARG_U        ((1<<SIZE_U)-1)
-#define MAXARG_S        (MAXARG_U>>1)		/* `S' is signed */
-#else
-#define MAXARG_U        MAX_INT
-#define MAXARG_S        MAX_INT
-#endif
-
-#if SIZE_A < BITS_INT-1
-#define MAXARG_A        ((1<<SIZE_A)-1)
-#else
-#define MAXARG_A        MAX_INT
-#endif
-
-#if SIZE_B < BITS_INT-1
-#define MAXARG_B        ((1<<SIZE_B)-1)
-#else
-#define MAXARG_B        MAX_INT
-#endif
-
-
-/* maximum stack size in a function */
-#ifndef MAXSTACK
+/* maximum stack for a Lua function */
 #define MAXSTACK	250
-#endif
-
-#if MAXSTACK > MAXARG_B
-#undef MAXSTACK
-#define MAXSTACK	MAXARG_B
-#endif
 
 
 /* maximum number of local variables */
 #ifndef MAXLOCALS
 #define MAXLOCALS 200           /* arbitrary limit (<MAXSTACK) */
 #endif
-#if MAXLOCALS>=MAXSTACK
-#undef MAXLOCALS
-#define MAXLOCALS	(MAXSTACK-1)
-#endif
 
 
 /* maximum number of upvalues */
 #ifndef MAXUPVALUES
-#define MAXUPVALUES 32          /* arbitrary limit (<=MAXARG_B) */
-#endif
-#if MAXUPVALUES>MAXARG_B
-#undef MAXUPVALUES
-#define MAXUPVALUES	MAXARG_B
-#endif
-
-
-/* maximum number of variables in the left side of an assignment */
-#ifndef MAXVARSLH
-#define MAXVARSLH 100           /* arbitrary limit (<MULT_RET) */
-#endif
-#if MAXVARSLH>=MULT_RET
-#undef MAXVARSLH
-#define MAXVARSLH	(MULT_RET-1)
+#define MAXUPVALUES 32          /* arbitrary limit (<MAXSTACK) */
 #endif
 
 
@@ -182,27 +113,17 @@ typedef unsigned long Instruction;
 #ifndef MAXPARAMS
 #define MAXPARAMS 100           /* arbitrary limit (<MAXLOCALS) */
 #endif
-#if MAXPARAMS>=MAXLOCALS
-#undef MAXPARAMS
-#define MAXPARAMS	(MAXLOCALS-1)
-#endif
 
 
 /* number of list items to accumulate before a SETLIST instruction */
+/* (must be a power of 2) */
 #define LFIELDS_PER_FLUSH	64
-#if LFIELDS_PER_FLUSH>(MAXSTACK/4)
-#undef LFIELDS_PER_FLUSH
-#define LFIELDS_PER_FLUSH	(MAXSTACK/4)
-#endif
 
-/* number of record items to accumulate before a SETMAP instruction */
-/* (each item counts 2 elements on the stack: an index and a value) */
-#define RFIELDS_PER_FLUSH	(LFIELDS_PER_FLUSH/2)
 
 
 /* maximum lookback to find a real constant (for code generation) */
 #ifndef LOOKBACKNUMS
-#define LOOKBACKNUMS    20      /* arbitrary constant */
+#define LOOKBACKNUMS    40      /* arbitrary constant */
 #endif
 
 

+ 3 - 5
lobject.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lobject.h,v 1.101 2001/03/07 18:09:25 roberto Exp roberto $
+** $Id: lobject.h,v 1.102 2001/04/11 14:42:41 roberto Exp roberto $
 ** Type definitions for Lua objects
 ** See Copyright Notice in lua.h
 */
@@ -114,10 +114,8 @@ union L_UTString {
 ** Function Prototypes
 */
 typedef struct Proto {
-  lua_Number *knum;  /* numbers used by the function */
-  int sizeknum;  /* size of `knum' */
-  struct TString **kstr;  /* strings used by the function */
-  int sizekstr;  /* size of `kstr' */
+  TObject *k;  /* constants used by the function */
+  int sizek;  /* size of `k' */
   struct Proto **kproto;  /* functions defined inside the function */
   int sizekproto;  /* size of `kproto' */
   Instruction *code;

+ 127 - 92
lopcodes.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lopcodes.h,v 1.71 2001/03/07 13:22:55 roberto Exp roberto $
+** $Id: lopcodes.h,v 1.72 2001/04/06 18:25:00 roberto Exp roberto $
 ** Opcodes for Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -12,29 +12,55 @@
 
 /*===========================================================================
   We assume that instructions are unsigned numbers.
-  All instructions have an opcode in the first 6 bits. Moreover,
-  an instruction can have 0, 1, or 2 arguments. Instructions can
-  have the following types:
-  type 0: no arguments
-  type 1: 1 unsigned argument in the higher bits (called `U')
-  type 2: 1 signed argument in the higher bits          (`S')
-  type 3: 1st unsigned argument in the higher bits      (`A')
-          2nd unsigned argument in the middle bits      (`B')
+  All instructions have an opcode in the first 6 bits.
+  Instructions can have the following fields:
+	`A' : 8 bits (25-32)
+	`B' : 8 bits (17-24)
+	`C' : 10 bits (7-16)
+	`Bc' : 18 bits (`B' and `C' together)
+	`sBc' : signed Bc
 
   A signed argument is represented in excess K; that is, the number
   value is the unsigned value minus K. K is exactly the maximum value
   for that argument (so that -max is represented by 0, and +max is
   represented by 2*max), which is half the maximum for the corresponding
   unsigned argument.
-
-  The size of each argument is defined in `llimits.h'. The usual is an
-  instruction with 32 bits, U arguments with 26 bits (32-6), B arguments
-  with 9 bits, and A arguments with 17 bits (32-6-9). For small
-  installations, the instruction size can be 16, so U has 10 bits,
-  and A and B have 5 bits each.
 ===========================================================================*/
 
 
+/*
+** size and position of opcode arguments.
+*/
+#define SIZE_C		10
+#define SIZE_B		8
+#define SIZE_Bc		(SIZE_C + SIZE_B)
+#define SIZE_A		8
+
+#define SIZE_OP		6
+
+#define POS_C		SIZE_OP
+#define POS_B		(POS_C + SIZE_C)
+#define POS_Bc		POS_C
+#define POS_A		(POS_B + SIZE_B)
+
+
+/*
+** limits for opcode arguments.
+** we use (signed) int to manipulate most arguments,
+** so they must fit in BITS_INT-1 bits (-1 for sign)
+*/
+#if SIZE_Bc < BITS_INT-1
+#define MAXARG_Bc        ((1<<SIZE_Bc)-1)
+#define MAXARG_sBc        (MAXARG_Bc>>1)         /* `sBc' is signed */
+#else
+#define MAXARG_Bc        MAX_INT
+#define MAXARG_sBc        MAX_INT
+#endif
+
+
+#define MAXARG_A        ((1<<SIZE_A)-1)
+#define MAXARG_B        ((1<<SIZE_B)-1)
+#define MAXARG_C        ((1<<SIZE_C)-1)
 
 
 /* creates a mask with `n' 1 bits at position `p' */
@@ -47,120 +73,129 @@
 ** the following macros help to manipulate instructions
 */
 
-#define CREATE_0(o)	 ((Instruction)(o))
 #define GET_OPCODE(i)	((OpCode)((i)&MASK1(SIZE_OP,0)))
-#define SET_OPCODE(i,o)	((i) = (((i)&MASK0(SIZE_OP,0)) | (Instruction)(o)))
-
-#define CREATE_U(o,u)	 ((Instruction)(o) | ((Instruction)(u)<<POS_U))
-#define GETARG_U(i)	((int)((i)>>POS_U))
-#define SETARG_U(i,u)	((i) = (((i)&MASK0(SIZE_U,POS_U)) | \
-                               ((Instruction)(u)<<POS_U)))
+#define SET_OPCODE(i,o)	(((i)&MASK0(SIZE_OP,0)) | (Instruction)(o))
 
-#define CREATE_S(o,s)	CREATE_U((o),(s)+MAXARG_S)
-#define GETARG_S(i)	(GETARG_U(i)-MAXARG_S)
-#define SETARG_S(i,s)	SETARG_U((i),(s)+MAXARG_S)
-
-
-#define CREATE_AB(o,a,b) ((Instruction)(o) | ((Instruction)(a)<<POS_A) \
-                                           |  ((Instruction)(b)<<POS_B))
 #define GETARG_A(i)	((int)((i)>>POS_A))
-#define SETARG_A(i,a)	((i) = (((i)&MASK0(SIZE_A,POS_A)) | \
-                               ((Instruction)(a)<<POS_A)))
+#define SETARG_A(i,u)	((i) = (((i)&MASK0(SIZE_A,POS_A)) | \
+                               ((Instruction)(u)<<POS_A)))
+
 #define GETARG_B(i)	((int)(((i)>>POS_B) & MASK1(SIZE_B,0)))
 #define SETARG_B(i,b)	((i) = (((i)&MASK0(SIZE_B,POS_B)) | \
                                ((Instruction)(b)<<POS_B)))
 
+#define GETARG_C(i)	((int)(((i)>>POS_C) & MASK1(SIZE_C,0)))
+#define SETARG_C(i,b)	((i) = (((i)&MASK0(SIZE_C,POS_C)) | \
+                               ((Instruction)(b)<<POS_C)))
+
+#define GETARG_Bc(i)	((int)(((i)>>POS_Bc) & MASK1(SIZE_Bc,0)))
+#define SETARG_Bc(i,b)	((i) = (((i)&MASK0(SIZE_Bc,POS_Bc)) | \
+                               ((Instruction)(b)<<POS_Bc)))
+
+#define GETARG_sBc(i)	(GETARG_Bc(i)-MAXARG_sBc)
+#define SETARG_sBc(i,b)	SETARG_Bc((i),(b)+MAXARG_sBc)
+
+
+#define CREATE_ABC(o,a,b,c)	((Instruction)(o) \
+			| ((Instruction)(a)<<POS_A) \
+			| ((Instruction)(b)<<POS_B) \
+			| ((Instruction)(c)<<POS_C))
+
+#define CREATE_ABc(o,a,bc)	((Instruction)(o) \
+			| ((Instruction)(a)<<POS_A) \
+			| ((Instruction)(bc)<<POS_Bc))
+
+
+
 
 /*
-** K = U argument used as index to `kstr'
-** J = S argument used as jump offset (relative to pc of next instruction)
-** L = unsigned argument used as index of local variable
-** N = U argument used as index to `knum'
+** an invalid register that fits in 8 bits
+*/
+#define NO_REG		MAXARG_A
+
+
+/*
+** R(x) - register
+** Kst(x) - constant (in constant table)
+** R/K(x) == if x < MAXSTACK then R(x) else Kst(x-MAXSTACK)
 */
 
 typedef enum {
 /*----------------------------------------------------------------------
-name		args	stack before	stack after	side effects
+name		args	description
 ------------------------------------------------------------------------*/
-OP_RETURN,/*	U	v_n-v_x(at u)	(return)	returns v_x-v_n	*/
-
-OP_CALL,/*	A B	v_n-v_1 f(at a)	r_b-r_1		f(v1,...,v_n)	*/
-
-OP_PUSHNIL,/*	U	-		nil_1-nil_u			*/
-OP_POP,/*	U	a_u-a_1		-				*/
+OP_MOVE,/*	A B	R(A) := R(B)					*/
+OP_LOADK,/*	A Bc	R(A) := Kst(Bc)					*/
+OP_LOADINT,/*	A sBc	R(A) := (Number)sBc				*/
+OP_LOADNIL,/*	A B	R(A) := ... := R(B) := nil			*/
+OP_LOADUPVAL,/*	A Bc	R(A) := UpValue[Bc]				*/
 
-OP_PUSHINT,/*	S	-		(lua_Number)s			*/
-OP_PUSHSTRING,/* K	-		KSTR[k]				*/
-OP_PUSHNUM,/*	N	-		KNUM[n]				*/
-OP_PUSHNEGNUM,/* N	-		-KNUM[n]			*/
+OP_GETGLOBAL,/*	A Bc	R(A) := Gbl[Kst(Bc)]				*/
+OP_GETTABLE,/*	A B C	R(A) := R(B)[R/K(C)]				*/
 
-OP_PUSHUPVALUE,/* U	-		Closure[u]			*/
+OP_SETGLOBAL,/*	A Bc	Gbl[Kst(Bc)] := R(A)				*/
+OP_SETTABLE,/*	A B C	R(B)[R/K(C)] := R(A)				*/
 
-OP_GETLOCAL,/*	L	-		LOC[l]				*/
-OP_GETGLOBAL,/*	K	-		VAR[KSTR[k]]			*/
+OP_NEWTABLE,/*	A Bc	R(A) := {} (size = Bc)				*/
 
-OP_GETTABLE,/*	-	i t		t[i]				*/
-OP_GETDOTTED,/*	K	t		t[KSTR[k]]			*/
-OP_GETINDEXED,/* L	t		t[LOC[l]]			*/
-OP_PUSHSELF,/*	K	t		t t[KSTR[k]]			*/
+OP_SELF,/*	A B C	R(A+1) := R(B); R(A) := R(B)[R/K(C)]		*/
 
-OP_CREATETABLE,/* U	-		newarray(size = u)		*/
+OP_ADD,/*	A B C	R(A) := R(B) + R/K(C)				*/
+OP_SUB,/*	A B C	R(A) := R(B) - R/K(C)				*/
+OP_MUL,/*	A B C	R(A) := R(B) * R/K(C)				*/
+OP_DIV,/*	A B C	R(A) := R(B) / R/K(C)				*/
+OP_POW,/*	A B C	R(A) := R(B) ^ R/K(C)				*/
+OP_UNM,/*	A B	R(A) := -R(B)					*/
+OP_NOT,/*	A B	R(A) := not R(B)				*/
 
-OP_SETLOCAL,/*	L	x		-		LOC[l]=x	*/
-OP_SETGLOBAL,/*	K	x		-		VAR[KSTR[k]]=x	*/
-OP_SETTABLE,/*	A B	v a_a-a_1 i t	(pops b values)	t[i]=v		*/
+OP_CONCAT,/*	A B C	R(A) := R(B).. ... ..R(C)			*/
 
-OP_SETLIST,/*	A B	v_n-v_1 v_b	v_b		v_b[i+a*FPF]=v_i */
-OP_SETMAP,/*	U	v_n k_n - v_1 k_1 v_u	v_u	v_u[k_i]=v_i	*/
+OP_JMP,/*	sBc	PC += sBc					*/
+OP_CJMP,/*	sBc	if test then PC += sBc		(see (1))	*/
 
-OP_ADD,/*	-	y x		x+y				*/
-OP_ADDI,/*	S	x		x+s				*/
-OP_SUB,/*	-	y x		x-y				*/
-OP_MULT,/*	-	y x		x*y				*/
-OP_DIV,/*	-	y x		x/y				*/
-OP_POW,/*	-	y x		x^y				*/
-OP_CONCAT,/*	U	v_u-v_1		v1..-..v_u			*/
-OP_MINUS,/*	-	x		-x				*/
-OP_NOT,/*	-	x		(x==nil)? 1 : nil		*/
+OP_TESTEQ,/*	B C	test := (R(B) == R/K(C))			*/
+OP_TESTNE,/*	B C	test := (R(B) ~= R/K(C))			*/
+OP_TESTLT,/*	B C	test := (R(B) < R/K(C))				*/
+OP_TESTLE,/*	B C	test := (R(B) <= R/K(C))			*/
+OP_TESTGT,/*	B C	test := (R(B) > R/K(C))				*/
+OP_TESTGE,/*	B C	test := (R(B) >= R/K(C))			*/
 
-OP_JMPNE,/*	J	y x		-		(x~=y)? PC+=s	*/
-OP_JMPEQ,/*	J	y x		-		(x==y)? PC+=s	*/
-OP_JMPLT,/*	J	y x		-		(x<y)? PC+=s	*/
-OP_JMPLE,/*	J	y x		-		(x<y)? PC+=s	*/
-OP_JMPGT,/*	J	y x		-		(x>y)? PC+=s	*/
-OP_JMPGE,/*	J	y x		-		(x>=y)? PC+=s	*/
+OP_TESTT,/*	A B	test := R(B); if (test) R(A) := R(B)		*/
+OP_TESTF,/*	A B	test := not R(B); if (test) R(A) := nil		*/
 
-OP_JMPT,/*	J	x		-		(x~=nil)? PC+=s	*/
-OP_JMPF,/*	J	x		-		(x==nil)? PC+=s	*/
-OP_JMPONT,/*	J	x		(x~=nil)? x : -	(x~=nil)? PC+=s	*/
-OP_JMPONF,/*	J	x		(x==nil)? x : -	(x==nil)? PC+=s	*/
-OP_JMP,/*	J	-		-		PC+=s		*/
+OP_NILJMP,/*	A	R(A) := nil; PC++;				*/
 
-OP_PUSHNILJMP,/* -	-		nil		PC++;		*/
+OP_CALL,/*	A B C	R(A), ... ,R(A+C-1) := R(A)(R(A+1), ... ,R(B-1))*/
+OP_RETURN,/*	A B	return R(A), ... ,R(B-1)	(see (3))	*/
 
-OP_FORPREP,/*	J							*/
-OP_FORLOOP,/*	J							*/
+OP_FORPREP,/*	A sBc							*/
+OP_FORLOOP,/*	A sBc							*/
 
-OP_LFORPREP,/*	J							*/
-OP_LFORLOOP,/*	J							*/
+OP_TFORPREP,/*	A sBc							*/
+OP_TFORLOOP,/*	A sBc							*/
 
-OP_CLOSURE/*	A B	v_b-v_1		closure(KPROTO[a], v_1-v_b)	*/
+OP_SETLIST,/*	A Bc	R(A)[Bc-Bc%FPF+i] := R(A+i), 1 <= i <= Bc%FPF+1	*/
+OP_SETLISTO,/*	A Bc							*/
 
+OP_CLOSURE /*	A Bc	R(A) := closure(KPROTO[Bc], R(A), ... ,R(A+n))	*/
 } OpCode;
 
+
 #define NUM_OPCODES	((int)OP_CLOSURE+1)
 
 
-#define ISJUMP(o)	(OP_JMPNE <= (o) && (o) <= OP_JMP)
 
+/*===========================================================================
+  Notes:
+  (1) In the current implementation there is no `test' variable;
+      instructions OP_TEST* and OP_CJMP must always occur together.
 
+  (2) In OP_CALL, if (B == NO_REG) then B = top. C is the number of returns,
+      and can be NO_REG. OP_CALL always set "top" to last_result+1, so
+      next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use "top".
 
-/* special code to fit a LUA_MULTRET inside an argB */
-#define MULT_RET        255	/* (<=MAXARG_B) */
-#if MULT_RET>MAXARG_B
-#undef MULT_RET
-#define MULT_RET	MAXARG_B
-#endif
+  (3) In OP_RETURN, if (B == NO_REG) then B = top.
+===========================================================================*/
 
 
 #endif

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 322 - 227
lparser.c


+ 19 - 13
lparser.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lparser.h,v 1.29 2000/12/28 12:55:41 roberto Exp roberto $
+** $Id: lparser.h,v 1.30 2001/02/20 18:28:11 roberto Exp roberto $
 ** LL(1) Parser and code generator for Lua
 ** See Copyright Notice in lua.h
 */
@@ -16,25 +16,32 @@
 */
 
 typedef enum {
-  VGLOBAL,
-  VLOCAL,
-  VINDEXED,
-  VEXP
+  VVOID,	/* no value */
+  VNIL,
+  VNUMBER,	/* n = value */
+  VK,		/* info = index of constant in `k' */
+  VGLOBAL,	/* info = index of global name in `k' */
+  VLOCAL,	/* info = local register */
+  VINDEXED,	/* info = table register; aux = index register (or `k') */
+  VRELOCABLE,	/* info = instruction pc */
+  VNONRELOC,	/* info = result register */
+  VJMP,		/* info = result register */
+  VCALL		/* info = result register */
 } expkind;
 
 typedef struct expdesc {
   expkind k;
   union {
-    int index;  /* VGLOBAL: `kstr' index of global name; VLOCAL: stack index */
     struct {
-      int t;  /* patch list of `exit when true' */
-      int f;  /* patch list of `exit when false' */
-    } l;
+      int info, aux;
+    } i;
+    lua_Number n;
   } u;
+  int t;  /* patch list of `exit when true' */
+  int f;  /* patch list of `exit when false' */
 } expdesc;
 
 
-
 /* state needed to generate code for a given function */
 typedef struct FuncState {
   Proto *f;  /* current function header */
@@ -44,10 +51,9 @@ typedef struct FuncState {
   int pc;  /* next position to code (equivalent to `ncode') */
   int lasttarget;   /* `pc' of last `jump target' */
   int jlt;  /* list of jumps to `lasttarget' */
-  int stacklevel;  /* number of values on activation register */
-  int nkstr;  /* number of elements in `kstr' */
+  int freereg;  /* first free register */
+  int nk;  /* number of elements in `k' */
   int nkproto;  /* number of elements in `kproto' */
-  int nknum;  /* number of elements in `knum' */
   int nlineinfo;  /* number of elements in `lineinfo' */
   int nlocvars;  /* number of elements in `locvars' */
   int nactloc;  /* number of active local variables */

+ 56 - 77
ltests.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ltests.c,v 1.79 2001/04/17 17:35:54 roberto Exp roberto $
+** $Id: ltests.c,v 1.80 2001/04/23 16:35:45 roberto Exp roberto $
 ** Internal Module for Debugging of the Lua Implementation
 ** See Copyright Notice in lua.h
 */
@@ -140,77 +140,65 @@ void *debug_realloc (void *block, size_t oldsize, size_t size) {
 
 
 static const l_char *const instrname[NUM_OPCODES] = {
-  l_s("RETURN"),
-  l_s("CALL"),
-  l_s("PUSHNIL"),
-  l_s("POP"),
-  l_s("PUSHINT"),
-  l_s("PUSHSTRING"),
-  l_s("PUSHNUM"),
-  l_s("PUSHNEGNUM"),
-  l_s("PUSHUPVALUE"),
-  l_s("GETLOCAL"),
-  l_s("GETGLOBAL"),
-  l_s("GETTABLE"),
-  l_s("GETDOTTED"),
-  l_s("GETINDEXED"),
-  l_s("PUSHSELF"),
-  l_s("CREATETABLE"),
-  l_s("SETLOCAL"),
-  l_s("SETGLOBAL"),
-  l_s("SETTABLE"),
-  l_s("SETLIST"),
-  l_s("SETMAP"),
-  l_s("ADD"),
-  l_s("ADDI"),
-  l_s("SUB"),
-  l_s("MULT"),
-  l_s("DIV"),
-  l_s("POW"),
-  l_s("CONCAT"),
-  l_s("MINUS"),
-  l_s("NOT"),
-  l_s("JMPNE"),
-  l_s("JMPEQ"),
-  l_s("JMPLT"),
-  l_s("JMPLE"),
-  l_s("JMPGT"),
-  l_s("JMPGE"),
-  l_s("JMPT"),
-  l_s("JMPF"),
-  l_s("JMPONT"),
-  l_s("JMPONF"),
-  l_s("JMP"),
-  l_s("PUSHNILJMP"),
-  l_s("FORPREP"),
-  l_s("FORLOOP"),
-  l_s("LFORPREP"),
-  l_s("LFORLOOP"),
-  l_s("CLOSURE")
+  l_s("OP_MOVE"),
+  l_s("OP_LOADK"),
+  l_s("OP_LOADINT"),
+  l_s("OP_LOADNIL"),
+  l_s("OP_LOADUPVAL"),
+  l_s("OP_GETGLOBAL"),
+  l_s("OP_GETTABLE"),
+  l_s("OP_SETGLOBAL"),
+  l_s("OP_SETTABLE"),
+  l_s("OP_NEWTABLE"),
+  l_s("OP_SELF"),
+  l_s("OP_ADD"),
+  l_s("OP_SUB"),
+  l_s("OP_MUL"),
+  l_s("OP_DIV"),
+  l_s("OP_POW"),
+  l_s("OP_UNM"),
+  l_s("OP_NOT"),
+  l_s("OP_CONCAT"),
+  l_s("OP_JMP"),
+  l_s("OP_CJMP"),
+  l_s("OP_TESTEQ"),
+  l_s("OP_TESTNE"),
+  l_s("OP_TESTLT"),
+  l_s("OP_TESTLE"),
+  l_s("OP_TESTGT"),
+  l_s("OP_TESTGE"),
+  l_s("OP_TESTT"),
+  l_s("OP_TESTF"),
+  l_s("OP_NILJMP"),
+  l_s("OP_CALL"),
+  l_s("OP_RETURN"),
+  l_s("OP_FORPREP"),
+  l_s("OP_FORLOOP"),
+  l_s("OP_LFORPREP"),
+  l_s("OP_LFORLOOP"),
+  l_s("OP_SETLIST"),
+  l_s("OP_CLOSURE")
 };
 
 
-static void pushop (lua_State *L, Proto *p, int pc) {
-  l_char buff[100];
+static l_char *buildop (Proto *p, int pc, l_char *buff) {
   Instruction i = p->code[pc];
   OpCode o = GET_OPCODE(i);
   const l_char *name = instrname[o];
-  sprintf(buff, l_s("%5d - "), luaG_getline(p->lineinfo, pc, 1, NULL));
-  switch ((enum Mode)luaK_opproperties[o].mode) {  
-    case iO:
-      sprintf(buff+8, l_s("%-12s"), name);
+  sprintf(buff, l_s("%4d - "), pc);
+  switch (getOpMode(o)) {  
+    case iABC:
+      sprintf(buff+strlen(buff), l_s("%-12s%4d %4d %4d"), name,
+              GETARG_A(i), GETARG_B(i), GETARG_C(i));
       break;
-    case iU:
-      sprintf(buff+8, l_s("%-12s%4u"), name, GETARG_U(i));
+    case iABc:
+      sprintf(buff+strlen(buff), l_s("%-12s%4d %4d"), name, GETARG_A(i), GETARG_Bc(i));
       break;
-    case iS:
-      sprintf(buff+8, l_s("%-12s%4d"), name, GETARG_S(i));
-      break;
-    case iAB:
-      sprintf(buff+8, l_s("%-12s%4d %4d"), name, GETARG_A(i), GETARG_B(i));
+    case iAsBc:
+      sprintf(buff+strlen(buff), l_s("%-12s%4d %4d"), name, GETARG_A(i), GETARG_sBc(i));
       break;
   }
-  lua_pushstring(L, buff);
+  return buff;
 }
 
 
@@ -224,24 +212,25 @@ static int listcode (lua_State *L) {
   setnameval(L, l_s("maxstack"), p->maxstacksize);
   setnameval(L, l_s("numparams"), p->numparams);
   for (pc=0; pc<p->sizecode; pc++) {
+    l_char buff[100];
     lua_pushnumber(L, pc+1);
-    pushop(L, p, pc);
+    lua_pushstring(L, buildop(p, pc, buff));
     lua_settable(L, -3);
   }
   return 1;
 }
 
 
-static int liststrings (lua_State *L) {
+static int listk (lua_State *L) {
   Proto *p;
   int i;
   luaL_arg_check(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1),
                  1, l_s("Lua function expected"));
   p = clvalue(luaA_index(L, 1))->f.l;
   lua_newtable(L);
-  for (i=0; i<p->sizekstr; i++) {
+  for (i=0; i<p->sizek; i++) {
     lua_pushnumber(L, i+1);
-    lua_pushstring(L, getstr(p->kstr[i]));
+    luaA_pushobject(L, p->k+i);
     lua_settable(L, -3);
   }
   return 1;
@@ -276,20 +265,10 @@ static int get_limits (lua_State *L) {
   lua_newtable(L);
   setnameval(L, l_s("BITS_INT"), BITS_INT);
   setnameval(L, l_s("LFPF"), LFIELDS_PER_FLUSH);
-  setnameval(L, l_s("MAXARG_A"), MAXARG_A);
-  setnameval(L, l_s("MAXARG_B"), MAXARG_B);
-  setnameval(L, l_s("MAXARG_S"), MAXARG_S);
-  setnameval(L, l_s("MAXARG_U"), MAXARG_U);
   setnameval(L, l_s("MAXLOCALS"), MAXLOCALS);
   setnameval(L, l_s("MAXPARAMS"), MAXPARAMS);
   setnameval(L, l_s("MAXSTACK"), MAXSTACK);
   setnameval(L, l_s("MAXUPVALUES"), MAXUPVALUES);
-  setnameval(L, l_s("MAXVARSLH"), MAXVARSLH);
-  setnameval(L, l_s("RFPF"), RFIELDS_PER_FLUSH);
-  setnameval(L, l_s("SIZE_A"), SIZE_A);
-  setnameval(L, l_s("SIZE_B"), SIZE_B);
-  setnameval(L, l_s("SIZE_OP"), SIZE_OP);
-  setnameval(L, l_s("SIZE_U"), SIZE_U);
   return 1;
 }
 
@@ -700,7 +679,7 @@ static const struct luaL_reg tests_funcs[] = {
   {l_s("hash"), hash_query},
   {l_s("limits"), get_limits},
   {l_s("listcode"), listcode},
-  {l_s("liststrings"), liststrings},
+  {l_s("listk"), listk},
   {l_s("listlocals"), listlocals},
   {l_s("loadlib"), loadlib},
   {l_s("querystr"), string_query},

+ 231 - 245
lvm.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lvm.c,v 1.177 2001/03/26 14:31:49 roberto Exp roberto $
+** $Id: lvm.c,v 1.178 2001/04/06 18:25:00 roberto Exp roberto $
 ** Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -28,15 +28,14 @@
 
 
 
-int luaV_tonumber (TObject *obj) {
-  if (ttype(obj) != LUA_TSTRING)
-    return 1;
-  else {
-    if (!luaO_str2d(svalue(obj), &nvalue(obj)))
-      return 2;
-    ttype(obj) = LUA_TNUMBER;
-    return 0;
+const TObject *luaV_tonumber (const TObject *obj, TObject *n) {
+  if (ttype(obj) == LUA_TNUMBER) return obj;
+  if (ttype(obj) == LUA_TSTRING && luaO_str2d(svalue(obj), &nvalue(n))) {
+    ttype(n) = LUA_TNUMBER;
+    return n;
   }
+  else
+    return NULL;
 }
 
 
@@ -148,8 +147,7 @@ void luaV_gettable (lua_State *L, StkId t, TObject *key, StkId res) {
       }
     }
     /* else will call the tag method */
-  }
-  else {  /* not a table; try a `gettable' tag method */
+  } else {  /* not a table; try a `gettable' tag method */
     tm = luaT_gettmbyObj(G(L), t, TM_GETTABLE);
     if (tm == NULL)  /* no tag method? */
       luaG_typeerror(L, t, l_s("index"));
@@ -162,7 +160,7 @@ void luaV_gettable (lua_State *L, StkId t, TObject *key, StkId res) {
 /*
 ** Receives table at `t', key at `key' and value at `val'.
 */
-void luaV_settable (lua_State *L, StkId t, StkId key, StkId val) {
+void luaV_settable (lua_State *L, StkId t, TObject *key, StkId val) {
   Closure *tm;
   if (ttype(t) == LUA_TTABLE) {  /* `t' is a table? */
     int tg = hvalue(t)->htag;
@@ -172,8 +170,7 @@ void luaV_settable (lua_State *L, StkId t, StkId key, StkId val) {
       return;
     }
     /* else will call the tag method */
-  }
-  else {  /* not a table; try a `settable' tag method */
+  } else {  /* not a table; try a `settable' tag method */
     tm = luaT_gettmbyObj(G(L), t, TM_SETTABLE);
     if (tm == NULL)  /* no tag method? */
       luaG_typeerror(L, t, l_s("index"));
@@ -188,8 +185,7 @@ void luaV_getglobal (lua_State *L, TString *name, StkId res) {
   if (!HAS_TM_GETGLOBAL(L, ttype(value)) ||  /* is there a tag method? */
       (tm = luaT_gettmbyObj(G(L), value, TM_GETGLOBAL)) == NULL) {
     setobj(res, value);  /* default behavior */
-  }
-  else
+  } else
     callTM(L, l_s("csor"), tm, name, value, res);
 }
 
@@ -200,8 +196,7 @@ void luaV_setglobal (lua_State *L, TString *name, StkId val) {
   if (!HAS_TM_SETGLOBAL(L, ttype(oldvalue)) ||  /* no tag methods? */
      (tm = luaT_gettmbyObj(G(L), oldvalue, TM_SETGLOBAL)) == NULL) {
     setobj(oldvalue, val);  /* raw set */
-  }
-  else
+  } else
     callTM(L, l_s("csoo"), tm, name, oldvalue, val);
 }
 
@@ -224,9 +219,10 @@ static int call_binTM (lua_State *L, const TObject *p1, const TObject *p2,
 }
 
 
-static void call_arith (lua_State *L, StkId p1, TMS event) {
-  if (!call_binTM(L, p1, p1+1, p1, event))
-    luaG_binerror(L, p1, LUA_TNUMBER, l_s("perform arithmetic on"));
+static void call_arith (lua_State *L, StkId p1, TObject *p2,
+                        StkId res, TMS event) {
+  if (!call_binTM(L, p1, p2, res, event))
+    luaG_aritherror(L, p1, p2);
 }
 
 
@@ -270,9 +266,8 @@ void luaV_strconc (lua_State *L, int total, StkId top) {
     int n = 2;  /* number of elements handled in this pass (at least 2) */
     if (tostring(L, top-2) || tostring(L, top-1)) {
       if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT))
-        luaG_binerror(L, top-2, LUA_TSTRING, l_s("concat"));
-    }
-    else if (tsvalue(top-1)->len > 0) {  /* if len=0, do nothing */
+        luaG_concaterror(L, top-2, top-1);
+    } else if (tsvalue(top-1)->len > 0) {  /* if len=0, do nothing */
       /* at least two string values; get as many as possible */
       lu_mem tl = (lu_mem)tsvalue(top-1)->len + (lu_mem)tsvalue(top-2)->len;
       l_char *buffer;
@@ -321,7 +316,32 @@ static void adjust_varargs (lua_State *L, StkId base, int nfixargs) {
 
 
 
-#define dojump(pc, i)	((pc) += GETARG_S(i))
+/*
+** some macros for common tasks in `luaV_execute'
+*/
+
+#define runtime_check(L, c)	{ if (!(c)) return L->top; }
+
+#define RA(i)	(base+GETARG_A(i))
+#define RB(i)	(base+GETARG_B(i))
+#define RC(i)	(base+GETARG_C(i))
+#define RKC(i)	((GETARG_C(i) < MAXSTACK) ? \
+			base+GETARG_C(i) : \
+			tf->k+GETARG_C(i)-MAXSTACK)
+#define KBc(i)	(tf->k+GETARG_Bc(i))
+
+#define Arith(op, optm)	{ \
+  const TObject *b = RB(i); const TObject *c = RKC(i);		\
+  TObject tempb, tempc; \
+  if ((ttype(b) == LUA_TNUMBER || (b = luaV_tonumber(b, &tempb)) != NULL) && \
+      (ttype(c) == LUA_TNUMBER || (c = luaV_tonumber(c, &tempc)) != NULL)) { \
+    setnvalue(RA(i), nvalue(b) op nvalue(c));		\
+  } else		\
+    call_arith(L, RB(i), RKC(i), RA(i), optm); \
+}
+
+
+#define dojump(pc, i)	((pc) += GETARG_sBc(i))
 
 /*
 ** Executes the given Lua function. Parameters are between [base,top).
@@ -329,328 +349,294 @@ static void adjust_varargs (lua_State *L, StkId base, int nfixargs) {
 */
 StkId luaV_execute (lua_State *L, const Closure *cl, StkId base) {
   const Proto *const tf = cl->f.l;
-  StkId top;  /* keep top local, for performance */
-  const Instruction *pc = tf->code;
-  const lua_Hook linehook = L->linehook;
-  L->ci->pc = &pc;
+  const Instruction *pc;
+  lua_Hook linehook;
   if (tf->is_vararg)  /* varargs? */
     adjust_varargs(L, base, tf->numparams);
   luaD_adjusttop(L, base, tf->maxstacksize);
-  top = base+tf->numparams+tf->is_vararg;
+  pc = tf->code;
+  L->ci->pc = &pc;
+  linehook = L->linehook;
   /* main loop of interpreter */
   for (;;) {
     const Instruction i = *pc++;
-    lua_assert(L->top == base+tf->maxstacksize);
     if (linehook)
       traceexec(L, linehook);
     switch (GET_OPCODE(i)) {
-      case OP_RETURN: {
-        L->top = top;
-        return base+GETARG_U(i);
-      }
-      case OP_CALL: {
-        int nres = GETARG_B(i);
-        if (nres == MULT_RET) nres = LUA_MULTRET;
-        L->top = top;
-        luaD_call(L, base+GETARG_A(i), nres);
-        top = L->top;
-        L->top = base+tf->maxstacksize;
-        break;
-      }
-      case OP_PUSHNIL: {
-        int n = GETARG_U(i);
-        lua_assert(n>0);
-        do {
-          setnilvalue(top++);
-        } while (--n > 0);
-        break;
-      }
-      case OP_POP: {
-        top -= GETARG_U(i);
-        break;
-      }
-      case OP_PUSHINT: {
-        setnvalue(top, (lua_Number)GETARG_S(i));
-        top++;
-        break;
-      }
-      case OP_PUSHSTRING: {
-        setsvalue(top, tf->kstr[GETARG_U(i)]);
-        top++;
+      case OP_MOVE: {
+        setobj(RA(i), RB(i));
         break;
       }
-      case OP_PUSHNUM: {
-        setnvalue(top, tf->knum[GETARG_U(i)]);
-        top++;
+      case OP_LOADK: {
+        setobj(RA(i), KBc(i));
         break;
       }
-      case OP_PUSHNEGNUM: {
-        setnvalue(top, -tf->knum[GETARG_U(i)]);
-        top++;
+      case OP_LOADINT: {
+        setnvalue(RA(i), (lua_Number)GETARG_sBc(i));
         break;
       }
-      case OP_PUSHUPVALUE: {
-        setobj(top++, &cl->upvalue[GETARG_U(i)]);
+      case OP_LOADUPVAL: {
+        setobj(RA(i), cl->upvalue+GETARG_Bc(i));
         break;
       }
-      case OP_GETLOCAL: {
-        setobj(top++, base+GETARG_U(i));
+      case OP_LOADNIL: {
+        TObject *ra = RA(i);
+        TObject *rb = RB(i);
+        do {
+          setnilvalue(ra++);
+        } while (ra <= rb);
         break;
       }
       case OP_GETGLOBAL: {
-        luaV_getglobal(L, tf->kstr[GETARG_U(i)], top);
-        top++;
+        lua_assert(ttype(KBc(i)) == LUA_TSTRING);
+        luaV_getglobal(L, tsvalue(KBc(i)), RA(i));
         break;
       }
       case OP_GETTABLE: {
-        top--;
-        luaV_gettable(L, top-1, top, top-1);
-        break;
-      }
-      case OP_GETDOTTED: {
-        setsvalue(top, tf->kstr[GETARG_U(i)]);
-        luaV_gettable(L, top-1, top, top-1);
-        break;
-      }
-      case OP_GETINDEXED: {
-        luaV_gettable(L, top-1, base+GETARG_U(i), top-1);
-        break;
-      }
-      case OP_PUSHSELF: {
-        setobj(top, top-1);
-        setsvalue(top+1, tf->kstr[GETARG_U(i)]);
-        luaV_gettable(L, top-1, top+1, top-1);
-        top++;
-        break;
-      }
-      case OP_CREATETABLE: {
-        luaC_checkGC(L);
-        sethvalue(top, luaH_new(L, GETARG_U(i)));
-        top++;
-        break;
-      }
-      case OP_SETLOCAL: {
-        setobj(base+GETARG_U(i), --top);
+        luaV_gettable(L, RB(i), RKC(i), RA(i));
         break;
       }
       case OP_SETGLOBAL: {
-        top--;
-        luaV_setglobal(L, tf->kstr[GETARG_U(i)], top);
+        lua_assert(ttype(KBc(i)) == LUA_TSTRING);
+        luaV_setglobal(L, tsvalue(KBc(i)), RA(i));
         break;
       }
       case OP_SETTABLE: {
-        StkId t = top-GETARG_A(i);
-        luaV_settable(L, t, t+1, top-1);
-        top -= GETARG_B(i);  /* pop values */
+        luaV_settable(L, RB(i), RKC(i), RA(i));
         break;
       }
-      case OP_SETLIST: {
-        int aux = GETARG_A(i) * LFIELDS_PER_FLUSH;
-        TObject *t = base+GETARG_B(i);
-        Hash *h = hvalue(t);
-        int n;
-        for (n = top-t-1; n; n--)
-          setobj(luaH_setnum(L, h, n+aux), --top);
+      case OP_NEWTABLE: {
+        luaC_checkGC(L);
+        sethvalue(RA(i), luaH_new(L, GETARG_Bc(i)));
         break;
       }
-      case OP_SETMAP: {
-        TObject *t = base+GETARG_U(i);
-        Hash *h = hvalue(t);
-        while (top-1 > t) {
-          top-=2;
-          setobj(luaH_set(L, h, top), top+1);
-        }
+      case OP_SELF: {
+        StkId ra = RA(i);
+        StkId rb = RB(i);
+        setobj(ra+1, rb);
+        luaV_gettable(L, rb, RKC(i), ra);
         break;
       }
       case OP_ADD: {
-        if (tonumber(top-2) || tonumber(top-1))
-          call_arith(L, top-2, TM_ADD);
-        else
-          nvalue(top-2) += nvalue(top-1);
-        top--;
-        break;
-      }
-      case OP_ADDI: {
-        if (tonumber(top-1)) {
-          setnvalue(top, (lua_Number)GETARG_S(i));
-          call_arith(L, top-1, TM_ADD);
-        }
-        else
-          nvalue(top-1) += (lua_Number)GETARG_S(i);
+        Arith( + , TM_ADD);
         break;
       }
       case OP_SUB: {
-        if (tonumber(top-2) || tonumber(top-1))
-          call_arith(L, top-2, TM_SUB);
-        else
-          nvalue(top-2) -= nvalue(top-1);
-        top--;
+        Arith( - , TM_SUB);
         break;
       }
-      case OP_MULT: {
-        if (tonumber(top-2) || tonumber(top-1))
-          call_arith(L, top-2, TM_MUL);
-        else
-          nvalue(top-2) *= nvalue(top-1);
-        top--;
+      case OP_MUL: {
+        Arith( * , TM_MUL);
         break;
       }
       case OP_DIV: {
-        if (tonumber(top-2) || tonumber(top-1))
-          call_arith(L, top-2, TM_DIV);
-        else
-          nvalue(top-2) /= nvalue(top-1);
-        top--;
+        Arith( / , TM_DIV);
         break;
       }
       case OP_POW: {
-        if (!call_binTM(L, top-2, top-1, top-2, TM_POW))
-          luaD_error(L, l_s("undefined operation"));
-        top--;
+        call_arith(L, RB(i), RKC(i), RA(i), TM_POW);
         break;
       }
-      case OP_CONCAT: {
-        int n = GETARG_U(i);
-        luaV_strconc(L, n, top);
-        top -= n-1;
-        luaC_checkGC(L);
-        break;
-      }
-      case OP_MINUS: {
-        if (tonumber(top-1)) {
-          setnilvalue(top);
-          call_arith(L, top-1, TM_UNM);
+      case OP_UNM: {
+        const TObject *rb = RB(i);
+        StkId ra = RA(i);
+        if (ttype(rb) == LUA_TNUMBER || (rb=luaV_tonumber(rb, ra)) != NULL) {
+          setnvalue(ra, -nvalue(rb));
+        }
+        else {
+          TObject temp;
+          setnilvalue(&temp);
+          call_arith(L, RB(i), &temp, ra, TM_UNM);
         }
-        else
-          nvalue(top-1) = -nvalue(top-1);
         break;
       }
       case OP_NOT: {
-        ttype(top-1) =
-           (ttype(top-1) == LUA_TNIL) ? LUA_TNUMBER : LUA_TNIL;
-        nvalue(top-1) = 1;
+        if (ttype(RB(i)) == LUA_TNIL) {
+          setnvalue(RA(i), 1);
+        } else {
+          setnilvalue(RA(i));
+        }
         break;
       }
-      case OP_JMPNE: {
-        top -= 2;
-        if (!luaO_equalObj(top, top+1)) dojump(pc, i);
+      case OP_CONCAT: {
+        StkId top = RC(i)+1;
+        StkId rb = RB(i);
+        luaV_strconc(L, top-rb, top);
+        setobj(RA(i), rb);
+        luaC_checkGC(L);
         break;
       }
-      case OP_JMPEQ: {
-        top -= 2;
-        if (luaO_equalObj(top, top+1)) dojump(pc, i);
+      case OP_CJMP:
+      case OP_JMP: {
+        dojump(pc, i);
         break;
       }
-      case OP_JMPLT: {
-        top -= 2;
-        if (luaV_lessthan(L, top, top+1)) dojump(pc, i);
+      case OP_TESTEQ: {
+        lua_assert(GET_OPCODE(*pc) == OP_CJMP);
+        if (luaO_equalObj(RB(i), RKC(i))) dojump(pc, *pc);
+        pc++;
         break;
       }
-      case OP_JMPLE: {  /* a <= b  ===  !(b<a) */
-        top -= 2;
-        if (!luaV_lessthan(L, top+1, top)) dojump(pc, i);
+      case OP_TESTNE: {
+        lua_assert(GET_OPCODE(*pc) == OP_CJMP);
+        if (!luaO_equalObj(RB(i), RKC(i))) dojump(pc, *pc);
+        pc++;
         break;
       }
-      case OP_JMPGT: {  /* a > b  ===  (b<a) */
-        top -= 2;
-        if (luaV_lessthan(L, top+1, top)) dojump(pc, i);
+      case OP_TESTLT: {
+        lua_assert(GET_OPCODE(*pc) == OP_CJMP);
+        if (luaV_lessthan(L, RB(i), RKC(i))) dojump(pc, *pc);
+        pc++;
         break;
       }
-      case OP_JMPGE: {  /* a >= b  ===  !(a<b) */
-        top -= 2;
-        if (!luaV_lessthan(L, top, top+1)) dojump(pc, i);
+      case OP_TESTLE: {  /* b <= c  ===  !(c<b) */
+        lua_assert(GET_OPCODE(*pc) == OP_CJMP);
+        if (!luaV_lessthan(L, RKC(i), RB(i))) dojump(pc, *pc);
+        pc++;
         break;
       }
-      case OP_JMPT: {
-        if (ttype(--top) != LUA_TNIL) dojump(pc, i);
+      case OP_TESTGT: {  /* b > c  ===  (c<b) */
+        lua_assert(GET_OPCODE(*pc) == OP_CJMP);
+        if (luaV_lessthan(L, RKC(i), RB(i))) dojump(pc, *pc);
+        pc++;
         break;
       }
-      case OP_JMPF: {
-        if (ttype(--top) == LUA_TNIL) dojump(pc, i);
+      case OP_TESTGE: {  /* b >= c  === !(b<c) */
+        lua_assert(GET_OPCODE(*pc) == OP_CJMP);
+        if (!luaV_lessthan(L, RB(i), RKC(i))) dojump(pc, *pc);
+        pc++;
         break;
       }
-      case OP_JMPONT: {
-        if (ttype(top-1) == LUA_TNIL) top--;
-        else dojump(pc, i);
+      case OP_TESTT: {
+        StkId rb = RB(i);
+        lua_assert(GET_OPCODE(*pc) == OP_CJMP);
+        if (ttype(rb) != LUA_TNIL) {
+          int a = GETARG_A(i);
+          if (a != NO_REG) setobj(base+a, rb);
+          dojump(pc, *pc);
+        }
+        pc++;
         break;
       }
-      case OP_JMPONF: {
-        if (ttype(top-1) != LUA_TNIL) top--;
-        else dojump(pc, i);
+      case OP_TESTF: {
+        lua_assert(GET_OPCODE(*pc) == OP_CJMP);
+        if (ttype(RB(i)) == LUA_TNIL) {
+          int a = GETARG_A(i);
+          if (a != NO_REG) setnilvalue(base+a);
+          dojump(pc, *pc);
+        }
+        pc++;
         break;
       }
-      case OP_JMP: {
-        dojump(pc, i);
+      case OP_NILJMP: {
+        setnilvalue(RA(i));
+        pc++;
         break;
       }
-      case OP_PUSHNILJMP: {
-        setnilvalue(top++);
-        pc++;
+      case OP_CALL: {
+        int nres;
+        int b = GETARG_B(i);
+        if (b != NO_REG)
+          L->top = base+b;
+        nres = GETARG_C(i);
+        if (nres == NO_REG) nres = LUA_MULTRET;
+        luaD_call(L, RA(i), nres);
+        if (nres != LUA_MULTRET) {
+          lua_assert(L->top == RA(i)+nres);
+          L->top = base+tf->maxstacksize;
+        }
         break;
       }
+      case OP_RETURN: {
+        int b = GETARG_B(i);
+        if (b != NO_REG)
+          L->top = base+b;
+        return RA(i);
+      }
       case OP_FORPREP: {
-        int jmp = GETARG_S(i);
-        if (tonumber(top-1))
-          luaD_error(L, l_s("`for' step must be a number"));
-        if (tonumber(top-2))
-          luaD_error(L, l_s("`for' limit must be a number"));
-        if (tonumber(top-3))
+        int jmp = GETARG_sBc(i);
+        StkId breg = RA(i);
+        if (luaV_tonumber(breg, breg) == NULL)
           luaD_error(L, l_s("`for' initial value must be a number"));
+        if (luaV_tonumber(breg+1, breg+1) == NULL)
+          luaD_error(L, l_s("`for' limit must be a number"));
+        if (luaV_tonumber(breg+2, breg+2) == NULL)
+          luaD_error(L, l_s("`for' step must be a number"));
         pc += -jmp;  /* `jump' to loop end (delta is negated here) */
-        goto forloop;  /* do not increment index */
+        nvalue(breg) -= nvalue(breg+2);/* decrement index (to be incremented) */
+        /* go through */
       }
       case OP_FORLOOP: {
-        lua_assert(ttype(top-1) == LUA_TNUMBER);
-        lua_assert(ttype(top-2) == LUA_TNUMBER);
-        if (ttype(top-3) != LUA_TNUMBER)
+        StkId breg = RA(i);
+        if (ttype(breg) != LUA_TNUMBER)
           luaD_error(L, l_s("`for' index must be a number"));
-        nvalue(top-3) += nvalue(top-1);  /* increment index */
-      forloop:
-        if (nvalue(top-1) > 0 ?
-            nvalue(top-3) > nvalue(top-2) :
-            nvalue(top-3) < nvalue(top-2))
-          top -= 3;  /* end loop: remove control variables */
-        else
+        runtime_check(L, ttype(breg+1) == LUA_TNUMBER &&
+                         ttype(breg+2) == LUA_TNUMBER);
+        nvalue(breg) += nvalue(breg+2);  /* increment index */
+        if (nvalue(breg+2) > 0 ?
+            nvalue(breg) <= nvalue(breg+1) :
+            nvalue(breg) >= nvalue(breg+1))
           dojump(pc, i);  /* repeat loop */
         break;
       }
-      case OP_LFORPREP: {
-        int jmp = GETARG_S(i);
-        if (ttype(top-1) != LUA_TTABLE)
+      case OP_TFORPREP: {
+        int jmp = GETARG_sBc(i);
+        StkId breg = RA(i);
+        if (ttype(breg) != LUA_TTABLE)
           luaD_error(L, l_s("`for' table must be a table"));
-        top += 3;  /* index,key,value */
-        setnvalue(top-3, -1);  /* initial index */
-        setnilvalue(top-2);
-        setnilvalue(top-1);
+        setnvalue(breg+1, -1);  /* initial index */
+        setnilvalue(breg+2);
+        setnilvalue(breg+3);
         pc += -jmp;  /* `jump' to loop end (delta is negated here) */
         /* go through */
       }
-      case OP_LFORLOOP: {
-        Hash *t = hvalue(top-4);
-        int n = (int)nvalue(top-3);
-        lua_assert(ttype(top-3) == LUA_TNUMBER);
-        lua_assert(ttype(top-4) == LUA_TTABLE);
+      case OP_TFORLOOP: {
+        StkId breg = RA(i);
+        Hash *t;
+        int n;
+        runtime_check(L, ttype(breg) == LUA_TTABLE);
+        runtime_check(L, ttype(breg+1) == LUA_TNUMBER);
+        t = hvalue(breg);
+        n = (int)nvalue(breg+1);
         n = luaH_nexti(t, n);
-        if (n == -1)  /* end loop? */
-          top -= 4;  /* remove table, index, key, and value */
-        else {
+        if (n != -1) {  /* repeat loop? */
           Node *node = node(t, n);
-          setnvalue(top-3, n);  /* index */
-          setkey2obj(top-2, node);
-          setobj(top-1, val(node));
+          setnvalue(breg+1, n);  /* index */
+          setkey2obj(breg+2, node);
+          setobj(breg+3, val(node));
           dojump(pc, i);  /* repeat loop */
         }
         break;
       }
+      case OP_SETLIST:
+      case OP_SETLISTO: {
+        int bc;
+        int n;
+        Hash *h;
+        StkId ra = RA(i);
+        runtime_check(L, ttype(ra) == LUA_TTABLE);
+        h = hvalue(ra);
+        bc = GETARG_Bc(i);
+        if (GET_OPCODE(i) == OP_SETLIST)
+          n = (bc&(LFIELDS_PER_FLUSH-1)) + 1;
+        else
+          n = L->top - ra - 1;
+        bc &= ~(LFIELDS_PER_FLUSH-1);  /* bc = bc - bc%FPF */
+        for (; n > 0; n--)
+          setobj(luaH_setnum(L, h, bc+n), ra+n);
+        break;
+      }
       case OP_CLOSURE: {
-        int nup = GETARG_B(i);
-        luaC_checkGC(L);
-        L->top = top;
-        luaV_Lclosure(L, tf->kproto[GETARG_A(i)], nup);
-        top -= (nup-1);
+        Proto *p = tf->kproto[GETARG_Bc(i)];
+        int nup = p->nupvalues;
+        StkId ra = RA(i);
+        L->top = ra+nup;
+        luaV_Lclosure(L, p, nup);
         L->top = base+tf->maxstacksize;
+        luaC_checkGC(L);
         break;
       }
     }
   }
 }
+

+ 3 - 4
lvm.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lvm.h,v 1.28 2001/02/01 16:03:38 roberto Exp roberto $
+** $Id: lvm.h,v 1.29 2001/02/07 18:13:49 roberto Exp roberto $
 ** Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -13,14 +13,13 @@
 #include "ltm.h"
 
 
-#define tonumber(o)   ((ttype(o) != LUA_TNUMBER) && (luaV_tonumber(o) != 0))
 #define tostring(L,o) ((ttype(o) != LUA_TSTRING) && (luaV_tostring(L, o) != 0))
 
 
-int luaV_tonumber (TObject *obj);
+const TObject *luaV_tonumber (const TObject *obj, TObject *n);
 int luaV_tostring (lua_State *L, TObject *obj);
 void luaV_gettable (lua_State *L, StkId t, TObject *key, StkId res);
-void luaV_settable (lua_State *L, StkId t, StkId key, StkId val);
+void luaV_settable (lua_State *L, StkId t, TObject *key, StkId val);
 void luaV_getglobal (lua_State *L, TString *s, StkId res);
 void luaV_setglobal (lua_State *L, TString *s, StkId val);
 StkId luaV_execute (lua_State *L, const Closure *cl, StkId base);

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác