Browse Source

new opcodes for table access with constant keys (strings and integers)

Roberto Ierusalimschy 8 years ago
parent
commit
502a1d1108
7 changed files with 245 additions and 99 deletions
  1. 56 18
      lcode.c
  2. 62 30
      ldebug.c
  3. 13 5
      lopcodes.c
  4. 11 9
      lopcodes.h
  5. 24 16
      lparser.c
  6. 16 8
      lparser.h
  7. 63 13
      lvm.c

+ 56 - 18
lcode.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lcode.c,v 2.116 2017/04/25 20:01:14 roberto Exp roberto $
+** $Id: lcode.c,v 2.117 2017/04/26 17:46:52 roberto Exp roberto $
 ** Code generator for Lua
 ** See Copyright Notice in lua.h
 */
@@ -580,18 +580,26 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) {
       e->k = VRELOCABLE;
       break;
     }
+    case VINDEXUP: {
+      e->u.info = luaK_codeABC(fs, OP_GETTABUP, 0, e->u.ind.t, e->u.ind.idx);
+      e->k = VRELOCABLE;
+      break;
+    }
+    case VINDEXI: {
+      freereg(fs, e->u.ind.t);
+      e->u.info = luaK_codeABC(fs, OP_GETI, 0, e->u.ind.t, e->u.ind.idx);
+      e->k = VRELOCABLE;
+      break;
+    }
+    case VINDEXSTR: {
+      freereg(fs, e->u.ind.t);
+      e->u.info = luaK_codeABC(fs, OP_GETFIELD, 0, e->u.ind.t, e->u.ind.idx);
+      e->k = VRELOCABLE;
+      break;
+    }
     case VINDEXED: {
-      OpCode op;
-      if (e->u.ind.vt == VLOCAL) {  /* is 't' in a register? */
-        freeregs(fs, e->u.ind.t, e->u.ind.idx);
-        op = OP_GETTABLE;
-      }
-      else {
-        lua_assert(e->u.ind.vt == VUPVAL);
-        freereg(fs, e->u.ind.idx);
-        op = OP_GETTABUP;  /* 't' is in an upvalue */
-      }
-      e->u.info = luaK_codeABC(fs, op, 0, e->u.ind.t, e->u.ind.idx);
+      freeregs(fs, e->u.ind.t, e->u.ind.idx);
+      e->u.info = luaK_codeABC(fs, OP_GETTABLE, 0, e->u.ind.t, e->u.ind.idx);
       e->k = VRELOCABLE;
       break;
     }
@@ -807,10 +815,24 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
       luaK_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0);
       break;
     }
+    case VINDEXUP: {
+      int e = luaK_exp2RK(fs, ex);
+      luaK_codeABC(fs, OP_SETTABUP, var->u.ind.t, var->u.ind.idx, e);
+      break;
+    }
+    case VINDEXI: {
+      int e = luaK_exp2RK(fs, ex);
+      luaK_codeABC(fs, OP_SETI, var->u.ind.t, var->u.ind.idx, e);
+      break;
+    }
+    case VINDEXSTR: {
+      int e = luaK_exp2RK(fs, ex);
+      luaK_codeABC(fs, OP_SETFIELD, var->u.ind.t, var->u.ind.idx, e);
+      break;
+    }
     case VINDEXED: {
-      OpCode op = (var->u.ind.vt == VLOCAL) ? OP_SETTABLE : OP_SETTABUP;
       int e = luaK_exp2RK(fs, ex);
-      luaK_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e);
+      luaK_codeABC(fs, OP_SETTABLE, var->u.ind.t, var->u.ind.idx, e);
       break;
     }
     default: lua_assert(0);  /* invalid var kind to store */
@@ -959,7 +981,8 @@ static void codenot (FuncState *fs, expdesc *e) {
 ** Check whether expression 'e' is a literal string
 */
 static int isKstr (FuncState *fs, expdesc *e) {
-  return (e->k == VK && ttisstring(&fs->f->k[e->u.info]));
+  return (e->k == VK && !hasjumps(e) && e->u.info <= MAXARG_C &&
+          ttisstring(&fs->f->k[e->u.info]));
 }
 
 
@@ -976,15 +999,30 @@ static int isKint (expdesc *e) {
 /*
 ** Create expression 't[k]'. 't' must have its final result already in a
 ** register or upvalue. Upvalues can only be indexed by literal strings.
+** Keys can be literal strings in the constant table or arbitrary
+** values in registers.
 */
 void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
   lua_assert(!hasjumps(t) && (vkisinreg(t->k) || t->k == VUPVAL));
   if (t->k == VUPVAL && !isKstr(fs, k))  /* upvalue indexed by non string? */
     luaK_exp2anyreg(fs, t);  /* put it in a register */
   t->u.ind.t = t->u.info;  /* register or upvalue index */
-  t->u.ind.idx = luaK_exp2RK(fs, k);  /* R/K index for key */
-  t->u.ind.vt = (t->k == VUPVAL) ? VUPVAL : VLOCAL;
-  t->k = VINDEXED;
+  if (t->k == VUPVAL) {
+    t->u.ind.idx = k->u.info;  /* literal string */
+    t->k = VINDEXUP;
+  }
+  else if (isKstr(fs, k)) {
+    t->u.ind.idx = k->u.info;  /* literal string */
+    t->k = VINDEXSTR;
+  }
+  else if (isKint(k)) {
+    t->u.ind.idx = k->u.ival;  /* integer constant */
+    t->k = VINDEXI;
+  }
+  else {
+    t->u.ind.idx = luaK_exp2anyreg(fs, k);  /* register */
+    t->k = VINDEXED;
+  }
 }
 
 

+ 62 - 30
ldebug.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ldebug.c,v 2.121 2016/10/19 12:32:10 roberto Exp roberto $
+** $Id: ldebug.c,v 2.122 2017/04/26 17:46:52 roberto Exp roberto $
 ** Debug Interface
 ** See Copyright Notice in lua.h
 */
@@ -350,28 +350,36 @@ static const char *getobjname (Proto *p, int lastpc, int reg,
 
 
 /*
-** find a "name" for the RK value 'c'
+** Find a "name" for the constant 'c'.
 */
-static void kname (Proto *p, int pc, int c, const char **name) {
-  if (ISK(c)) {  /* is 'c' a constant? */
-    TValue *kvalue = &p->k[INDEXK(c)];
-    if (ttisstring(kvalue)) {  /* literal constant? */
-      *name = svalue(kvalue);  /* it is its own name */
-      return;
-    }
-    /* else no reasonable name found */
-  }
-  else {  /* 'c' is a register */
-    const char *what = getobjname(p, pc, c, name); /* search for 'c' */
-    if (what && *what == 'c') {  /* found a constant name? */
-      return;  /* 'name' already filled */
-    }
-    /* else no reasonable name found */
-  }
-  *name = "?";  /* no reasonable name found */
+static void kname (Proto *p, int c, const char **name) {
+  TValue *kvalue = &p->k[INDEXK(c)];
+  *name = (ttisstring(kvalue)) ? svalue(kvalue) : "?";
+}
+
+
+/*
+** Find a "name" for the register 'c'.
+*/
+static void rname (Proto *p, int pc, int c, const char **name) {
+  const char *what = getobjname(p, pc, c, name); /* search for 'c' */
+  if (!(what && *what == 'c'))  /* did not find a constant name? */
+    *name = "?";
+}
+
+
+/*
+** Find a "name" for the R/K index 'c'.
+*/
+static void rkname (Proto *p, int pc, int c, const char **name) {
+  if (ISK(c))  /* is 'c' a constant? */
+    kname(p, INDEXK(c), name);
+  else  /* 'c' is a register */
+    rname(p, pc, c, name);
 }
 
 
+
 static int filterpc (int pc, int jmptarget) {
   if (pc < jmptarget)  /* is code conditional (inside a jump)? */
     return -1;  /* cannot know who sets that register */
@@ -428,8 +436,22 @@ static int findsetreg (Proto *p, int lastpc, int reg) {
 }
 
 
-static const char *getobjname (Proto *p, int lastpc, int reg,
-                               const char **name) {
+/*
+** Check whether table being indexed by instruction 'i' is the
+** environment '_ENV'
+*/
+static const char *gxf (Proto *p, int pc, Instruction i, int isup) {
+  int t = GETARG_B(i);  /* table index */
+  const char *name;  /* name of indexed variable */
+  if (isup)  /* is an upvalue? */
+    name = upvalname(p, t);
+  else
+    getobjname(p, pc, t, &name);
+  return (name && strcmp(name, LUA_ENV) == 0) ? "global" : "field";
+}
+
+
+ const char *getobjname (Proto *p, int lastpc, int reg, const char **name) {
   int pc;
   *name = luaF_getlocalname(p, reg + 1, lastpc);
   if (*name)  /* is a local? */
@@ -446,15 +468,24 @@ static const char *getobjname (Proto *p, int lastpc, int reg,
           return getobjname(p, pc, b, name);  /* get name for 'b' */
         break;
       }
-      case OP_GETTABUP:
+      case OP_GETTABUP: {
+        int k = GETARG_C(i);  /* key index */
+        kname(p, k, name);
+        return gxf(p, pc, i, 1);
+      }
       case OP_GETTABLE: {
         int k = GETARG_C(i);  /* key index */
-        int t = GETARG_B(i);  /* table index */
-        const char *vn = (op == OP_GETTABLE)  /* name of indexed variable */
-                         ? luaF_getlocalname(p, t + 1, pc)
-                         : upvalname(p, t);
-        kname(p, pc, k, name);
-        return (vn && strcmp(vn, LUA_ENV) == 0) ? "global" : "field";
+        rname(p, pc, k, name);
+        return gxf(p, pc, i, 0);
+      }
+      case OP_GETI: {
+        *name = "integer index";
+        return "field";
+      }
+      case OP_GETFIELD: {
+        int k = GETARG_C(i);  /* key index */
+        kname(p, k, name);
+        return gxf(p, pc, i, 0);
       }
       case OP_GETUPVAL: {
         *name = upvalname(p, GETARG_B(i));
@@ -472,7 +503,7 @@ static const char *getobjname (Proto *p, int lastpc, int reg,
       }
       case OP_SELF: {
         int k = GETARG_C(i);  /* key index */
-        kname(p, pc, k, name);
+        rkname(p, pc, k, name);
         return "method";
       }
       default: break;  /* go through to return NULL */
@@ -508,9 +539,10 @@ static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
     }
     /* other instructions can do calls through metamethods */
     case OP_SELF: case OP_GETTABUP: case OP_GETTABLE:
+    case OP_GETI: case OP_GETFIELD:
       tm = TM_INDEX;
       break;
-    case OP_SETTABUP: case OP_SETTABLE:
+    case OP_SETTABUP: case OP_SETTABLE: case OP_SETI: case OP_SETFIELD:
       tm = TM_NEWINDEX;
       break;
     case OP_ADDI:

+ 13 - 5
lopcodes.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lopcodes.c,v 1.56 2017/04/20 19:53:55 roberto Exp roberto $
+** $Id: lopcodes.c,v 1.57 2017/04/26 17:46:52 roberto Exp roberto $
 ** Opcodes for Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -25,11 +25,15 @@ LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = {
   "LOADBOOL",
   "LOADNIL",
   "GETUPVAL",
+  "SETUPVAL",
   "GETTABUP",
   "GETTABLE",
+  "GETI",
+  "GETFIELD",
   "SETTABUP",
-  "SETUPVAL",
   "SETTABLE",
+  "SETI",
+  "SETFIELD",
   "NEWTABLE",
   "SELF",
   "ADDI",
@@ -82,11 +86,15 @@ LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = {
  ,opmode(0, 1, OpArgU, OpArgU, iABC)		/* OP_LOADBOOL */
  ,opmode(0, 1, OpArgU, OpArgN, iABC)		/* OP_LOADNIL */
  ,opmode(0, 1, OpArgU, OpArgN, iABC)		/* OP_GETUPVAL */
+ ,opmode(0, 0, OpArgU, OpArgN, iABC)		/* OP_SETUPVAL */
  ,opmode(0, 1, OpArgU, OpArgK, iABC)		/* OP_GETTABUP */
- ,opmode(0, 1, OpArgR, OpArgK, iABC)		/* OP_GETTABLE */
+ ,opmode(0, 1, OpArgR, OpArgR, iABC)		/* OP_GETTABLE */
+ ,opmode(0, 1, OpArgR, OpArgU, iABC)		/* OP_GETI */
+ ,opmode(0, 1, OpArgR, OpArgK, iABC)		/* OP_GETFIELD */
  ,opmode(0, 0, OpArgK, OpArgK, iABC)		/* OP_SETTABUP */
- ,opmode(0, 0, OpArgU, OpArgN, iABC)		/* OP_SETUPVAL */
- ,opmode(0, 0, OpArgK, OpArgK, iABC)		/* OP_SETTABLE */
+ ,opmode(0, 0, OpArgR, OpArgK, iABC)		/* OP_SETTABLE */
+ ,opmode(0, 0, OpArgU, OpArgK, iABC)		/* OP_SETI */
+ ,opmode(0, 0, OpArgK, OpArgK, iABC)		/* OP_SETFIELD */
  ,opmode(0, 1, OpArgU, OpArgU, iABC)		/* OP_NEWTABLE */
  ,opmode(0, 1, OpArgR, OpArgK, iABC)		/* OP_SELF */
  ,opmode(0, 1, OpArgR, OpArgU, iABC)		/* OP_ADDI */

+ 11 - 9
lopcodes.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lopcodes.h,v 1.151 2017/04/24 20:26:39 roberto Exp roberto $
+** $Id: lopcodes.h,v 1.152 2017/04/26 17:46:52 roberto Exp roberto $
 ** Opcodes for Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -178,17 +178,21 @@ OP_LOADKX,/*	A 	R(A) := Kst(extra arg)				*/
 OP_LOADBOOL,/*	A B C	R(A) := (Bool)B; if (C) pc++			*/
 OP_LOADNIL,/*	A B	R(A), R(A+1), ..., R(A+B) := nil		*/
 OP_GETUPVAL,/*	A B	R(A) := UpValue[B]				*/
+OP_SETUPVAL,/*	A B	UpValue[B] := R(A)				*/
 
-OP_GETTABUP,/*	A B C	R(A) := UpValue[B][RK(C)]			*/
-OP_GETTABLE,/*	A B C	R(A) := R(B)[RK(C)]				*/
+OP_GETTABUP,/*	A B C	R(A) := UpValue[B][K(C):string]			*/
+OP_GETTABLE,/*	A B C	R(A) := R(B)[R(C)]				*/
+OP_GETI,/*	A B C	R(A) := R(B)[C]					*/
+OP_GETFIELD,/*	A B C	R(A) := R(B)[Kst(C):string]			*/
 
-OP_SETTABUP,/*	A B C	UpValue[A][RK(B)] := RK(C)			*/
-OP_SETUPVAL,/*	A B	UpValue[B] := R(A)				*/
-OP_SETTABLE,/*	A B C	R(A)[RK(B)] := RK(C)				*/
+OP_SETTABUP,/*	A B C	UpValue[A][K(B):string] := RK(C)		*/
+OP_SETTABLE,/*	A B C	R(A)[R(B)] := RK(C)				*/
+OP_SETI,/*	A B C	R(A)[B] := RK(C)				*/
+OP_SETFIELD,/*	A B C	R(A)[K(B):string] := RK(C)			*/
 
 OP_NEWTABLE,/*	A B C	R(A) := {} (size = B,C)				*/
 
-OP_SELF,/*	A B C	R(A+1) := R(B); R(A) := R(B)[RK(C)]		*/
+OP_SELF,/*	A B C	R(A+1) := R(B); R(A) := R(B)[RK(C):string]	*/
 
 OP_ADDI,/*	A B C	R(A) := R(B) + C				*/
 OP_ADD,/*	A B C	R(A) := RK(B) + RK(C)				*/
@@ -259,8 +263,6 @@ OP_EXTRAARG/*	Ax	extra (larger) argument for previous opcode	*/
 
   (*) In OP_LOADKX, the next 'instruction' is always EXTRAARG.
 
-  (*) In OP_GETTABUP, OP_SETTABUP, and OP_SELF, the index must be a string.
-
   (*) For comparisons, A specifies what condition the test should accept
   (true or false).
 

+ 24 - 16
lparser.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lparser.c,v 2.155 2016/08/01 19:51:24 roberto Exp roberto $
+** $Id: lparser.c,v 2.156 2017/04/20 19:53:55 roberto Exp roberto $
 ** Lua Parser
 ** See Copyright Notice in lua.h
 */
@@ -647,8 +647,7 @@ static void recfield (LexState *ls, struct ConsControl *cc) {
   /* recfield -> (NAME | '['exp1']') = exp1 */
   FuncState *fs = ls->fs;
   int reg = ls->fs->freereg;
-  expdesc key, val;
-  int rkkey;
+  expdesc tab, key, val;
   if (ls->t.token == TK_NAME) {
     checklimit(fs, cc->nh, MAX_INT, "items in a constructor");
     checkname(ls, &key);
@@ -657,9 +656,10 @@ static void recfield (LexState *ls, struct ConsControl *cc) {
     yindex(ls, &key);
   cc->nh++;
   checknext(ls, '=');
-  rkkey = luaK_exp2RK(fs, &key);
+  tab = *cc->t;
+  luaK_indexed(fs, &tab, &key);
   expr(ls, &val);
-  luaK_codeABC(fs, OP_SETTABLE, cc->t->u.info, rkkey, luaK_exp2RK(fs, &val));
+  luaK_storevar(fs, &tab, &val);
   fs->freereg = reg;  /* free registers */
 }
 
@@ -1121,17 +1121,25 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
   int extra = fs->freereg;  /* eventual position to save local variable */
   int conflict = 0;
   for (; lh; lh = lh->prev) {  /* check all previous assignments */
-    if (lh->v.k == VINDEXED) {  /* assigning to a table? */
-      /* table is the upvalue/local being assigned now? */
-      if (lh->v.u.ind.vt == v->k && lh->v.u.ind.t == v->u.info) {
-        conflict = 1;
-        lh->v.u.ind.vt = VLOCAL;
-        lh->v.u.ind.t = extra;  /* previous assignment will use safe copy */
+    if (vkisindexed(lh->v.k)) {  /* assignment to table field? */
+      if (lh->v.k == VINDEXUP) {  /* is table an upvalue? */
+        if (v->k == VUPVAL && lh->v.u.ind.t == v->u.info) {
+          conflict = 1;  /* table is the upvalue being assigned now */
+          lh->v.k = VINDEXSTR;
+          lh->v.u.ind.t = extra;  /* assignment will use safe copy */
+        }
       }
-      /* index is the local being assigned? (index cannot be upvalue) */
-      if (v->k == VLOCAL && lh->v.u.ind.idx == v->u.info) {
-        conflict = 1;
-        lh->v.u.ind.idx = extra;  /* previous assignment will use safe copy */
+      else {  /* table is a register */
+        if (v->k == VLOCAL && lh->v.u.ind.t == v->u.info) {
+          conflict = 1;  /* table is the local being assigned now */
+          lh->v.u.ind.t = extra;  /* assignment will use safe copy */
+        }
+        /* is index the local being assigned? */
+        if (lh->v.k == VINDEXED && v->k == VLOCAL &&
+            lh->v.u.ind.idx == v->u.info) {
+          conflict = 1;
+          lh->v.u.ind.idx = extra;  /* previous assignment will use safe copy */
+        }
       }
     }
   }
@@ -1151,7 +1159,7 @@ static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) {
     struct LHS_assign nv;
     nv.prev = lh;
     suffixedexp(ls, &nv.v);
-    if (nv.v.k != VINDEXED)
+    if (!vkisindexed(nv.v.k))
       check_conflict(ls, lh, &nv.v);
     checklimit(ls->fs, nvars + ls->L->nCcalls, LUAI_MAXCCALLS,
                     "C levels");

+ 16 - 8
lparser.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lparser.h,v 1.75 2015/12/17 15:44:50 roberto Exp roberto $
+** $Id: lparser.h,v 1.76 2015/12/30 18:16:13 roberto Exp roberto $
 ** Lua Parser
 ** See Copyright Notice in lua.h
 */
@@ -36,9 +36,17 @@ typedef enum {
   VLOCAL,  /* local variable; info = local register */
   VUPVAL,  /* upvalue variable; info = index of upvalue in 'upvalues' */
   VINDEXED,  /* indexed variable;
-                ind.vt = whether 't' is register or upvalue;
-                ind.t = table register or upvalue;
-                ind.idx = key's R/K index */
+                ind.t = table register;
+                ind.idx = key's R index */
+  VINDEXUP,  /* indexed upvalue;
+                ind.t = table upvalue;
+                ind.idx = key's K index */
+  VINDEXI, /* indexed variable with constant integer;
+                ind.t = table register;
+                ind.idx = key's value */
+  VINDEXSTR, /* indexed variable with literal string;
+                ind.t = table register;
+                ind.idx = key's K index */
   VJMP,  /* expression is a test/comparison;
             info = pc of corresponding jump instruction */
   VRELOCABLE,  /* expression can put result in any register;
@@ -48,7 +56,8 @@ typedef enum {
 } expkind;
 
 
-#define vkisvar(k)	(VLOCAL <= (k) && (k) <= VINDEXED)
+#define vkisvar(k)	(VLOCAL <= (k) && (k) <= VINDEXSTR)
+#define vkisindexed(k)	(VINDEXED <= (k) && (k) <= VINDEXSTR)
 #define vkisinreg(k)	((k) == VNONRELOC || (k) == VLOCAL)
 
 typedef struct expdesc {
@@ -57,10 +66,9 @@ typedef struct expdesc {
     lua_Integer ival;    /* for VKINT */
     lua_Number nval;  /* for VKFLT */
     int info;  /* for generic use */
-    struct {  /* for indexed variables (VINDEXED) */
-      short idx;  /* index (R/K) */
+    struct {  /* for indexed variables */
+      short idx;  /* index (R or "long" K) */
       lu_byte t;  /* table (register or upvalue) */
-      lu_byte vt;  /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */
     } ind;
   } u;
   int t;  /* patch list of 'exit when true' */

+ 63 - 13
lvm.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lvm.c,v 2.272 2017/04/24 20:26:39 roberto Exp roberto $
+** $Id: lvm.c,v 2.273 2017/04/26 17:46:52 roberto Exp roberto $
 ** Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -658,11 +658,13 @@ void luaV_finishOp (lua_State *L) {
   Instruction inst = *(ci->u.l.savedpc - 1);  /* interrupted instruction */
   OpCode op = GET_OPCODE(inst);
   switch (op) {  /* finish its execution */
-    case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_IDIV:
+    case OP_ADDI: case OP_ADD: case OP_SUB:
+    case OP_MUL: case OP_DIV: case OP_IDIV:
     case OP_BAND: case OP_BOR: case OP_BXOR: case OP_SHL: case OP_SHR:
     case OP_MOD: case OP_POW:
     case OP_UNM: case OP_BNOT: case OP_LEN:
-    case OP_GETTABUP: case OP_GETTABLE: case OP_SELF: {
+    case OP_GETTABUP: case OP_GETTABLE: case OP_GETI:
+    case OP_GETFIELD: case OP_SELF: {
       setobjs2s(L, base + GETARG_A(inst), --L->top);
       break;
     }
@@ -704,6 +706,7 @@ void luaV_finishOp (lua_State *L) {
       break;
     }
     case OP_TAILCALL: case OP_SETTABUP: case OP_SETTABLE:
+    case OP_SETI: case OP_SETFIELD:
       break;
     default: lua_assert(0);
   }
@@ -726,7 +729,9 @@ void luaV_finishOp (lua_State *L) {
 
 #define RA(i)	(base+GETARG_A(i))
 #define RB(i)	check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_Br(i))
+#define KB(i)	check_exp(getBMode(GET_OPCODE(i)) == OpArgK, k+GETARG_B(i))
 #define RC(i)	check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base+GETARG_C(i))
+#define KC(i)	check_exp(getCMode(GET_OPCODE(i)) == OpArgK, k+GETARG_C(i))
 #define RKB(i)	check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \
 	(GETARG_Bk(i)) ? k+GETARG_Br(i) : base+GETARG_Br(i))
 #define RKC(i)	check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \
@@ -837,10 +842,16 @@ void luaV_execute (lua_State *L) {
         setobj2s(L, ra, cl->upvals[b]->v);
         vmbreak;
       }
+      vmcase(OP_SETUPVAL) {
+        UpVal *uv = cl->upvals[GETARG_B(i)];
+        setobj(L, uv->v, ra);
+        luaC_barrier(L, uv, ra);
+        vmbreak;
+      }
       vmcase(OP_GETTABUP) {
         const TValue *slot;
         TValue *upval = cl->upvals[GETARG_B(i)]->v;
-        TValue *rc = RKC(i);
+        TValue *rc = KC(i);
         TString *key = tsvalue(rc);  /* key must be a string */
         if (luaV_fastget(L, upval, key, slot, luaH_getstr)) {
           setobj2s(L, ra, slot);
@@ -850,32 +861,71 @@ void luaV_execute (lua_State *L) {
       }
       vmcase(OP_GETTABLE) {
         StkId rb = RB(i);
-        TValue *rc = RKC(i);
+        TValue *rc = RC(i);
         gettableProtected(L, rb, rc, ra);
         vmbreak;
       }
+      vmcase(OP_GETI) {
+        const TValue *slot;
+        StkId rb = RB(i);
+        int c = GETARG_C(i);
+        if (luaV_fastget(L, rb, c, slot, luaH_getint)) {
+          setobj2s(L, ra, slot);
+        }
+        else {
+          TValue key;
+          setivalue(&key, c);
+          Protect(luaV_finishget(L, rb, &key, ra, slot));
+        }
+        vmbreak;
+      }
+      vmcase(OP_GETFIELD) {
+        const TValue *slot;
+        StkId rb = RB(i);
+        TValue *rc = KC(i);
+        TString *key = tsvalue(rc);  /* key must be a string */
+        if (luaV_fastget(L, rb, key, slot, luaH_getstr)) {
+          setobj2s(L, ra, slot);
+        }
+        else Protect(luaV_finishget(L, rb, rc, ra, slot));
+        vmbreak;
+      }
       vmcase(OP_SETTABUP) {
         const TValue *slot;
         TValue *upval = cl->upvals[GETARG_A(i)]->v;
-        TValue *rb = RKB(i);
+        TValue *rb = KB(i);
         TValue *rc = RKC(i);
         TString *key = tsvalue(rb);  /* key must be a string */
         if (!luaV_fastset(L, upval, key, slot, luaH_getstr, rc))
           Protect(luaV_finishset(L, upval, rb, rc, slot));
         vmbreak;
       }
-      vmcase(OP_SETUPVAL) {
-        UpVal *uv = cl->upvals[GETARG_B(i)];
-        setobj(L, uv->v, ra);
-        luaC_barrier(L, uv, ra);
-        vmbreak;
-      }
       vmcase(OP_SETTABLE) {
-        TValue *rb = RKB(i);
+        TValue *rb = RB(i);
         TValue *rc = RKC(i);
         settableProtected(L, ra, rb, rc);
         vmbreak;
       }
+      vmcase(OP_SETI) {
+        const TValue *slot;
+        int c = GETARG_B(i);
+        TValue *rc = RKC(i);
+        if (!luaV_fastset(L, ra, c, slot, luaH_getint, rc)) {
+          TValue key;
+          setivalue(&key, c);
+          Protect(luaV_finishset(L, ra, &key, rc, slot));
+        }
+        vmbreak;
+      }
+      vmcase(OP_SETFIELD) {
+        const TValue *slot;
+        TValue *rb = KB(i);
+        TValue *rc = RKC(i);
+        TString *key = tsvalue(rb);  /* key must be a string */
+        if (!luaV_fastset(L, ra, key, slot, luaH_getstr, rc))
+          Protect(luaV_finishset(L, ra, rb, rc, slot));
+        vmbreak;
+      }
       vmcase(OP_NEWTABLE) {
         int b = GETARG_B(i);
         int c = GETARG_C(i);