浏览代码

new method to handle tests without values (negative values)

Roberto Ierusalimschy 20 年之前
父节点
当前提交
3b19af44b0
共有 6 个文件被更改,包括 58 次插入40 次删除
  1. 39 30
      lcode.c
  2. 2 1
      lcode.h
  3. 4 2
      lopcodes.c
  4. 3 2
      lopcodes.h
  5. 3 4
      lparser.c
  6. 7 1
      lvm.c

+ 39 - 30
lcode.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lcode.c,v 2.14 2005/06/07 18:53:45 roberto Exp roberto $
+** $Id: lcode.c,v 2.15 2005/08/17 18:32:09 roberto Exp $
 ** Code generator for Lua
 ** See Copyright Notice in lua.h
 */
@@ -53,6 +53,11 @@ int luaK_jump (FuncState *fs) {
 }
 
 
+void luaK_ret (FuncState *fs, int first, int nret) {
+  luaK_codeABC(fs, OP_RETURN, first, nret+1, 0);
+}
+
+
 static int condjump (FuncState *fs, OpCode op, int A, int B, int C) {
   luaK_codeABC(fs, op, A, B, C);
   return luaK_jump(fs);
@@ -101,49 +106,50 @@ static Instruction *getjumpcontrol (FuncState *fs, int pc) {
 ** check whether list has any jump that do not produce a value
 ** (or produce an inverted value)
 */
-static int need_value (FuncState *fs, int list, int cond) {
+static int need_value (FuncState *fs, int list) {
   for (; list != NO_JUMP; list = getjump(fs, list)) {
     Instruction i = *getjumpcontrol(fs, list);
-    if (GET_OPCODE(i) != OP_TEST || GETARG_C(i) != cond) return 1;
+    if (GET_OPCODE(i) != OP_TESTSET) return 1;
   }
   return 0;  /* not found */
 }
 
 
 static void patchtestreg (Instruction *i, int reg) {
-  if (reg == NO_REG) reg = GETARG_B(*i);
-  SETARG_A(*i, reg);
+  if (reg != NO_REG)
+    SETARG_A(*i, reg);
+  else  /* no register to put value; change TESTSET to TEST */
+    *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i));
 }
 
 
-static void patchlistaux (FuncState *fs, int list,
-          int ttarget, int treg, int ftarget, int freg, int dtarget) {
+static void removevalues (FuncState *fs, int list) {
+  for (; list != NO_JUMP; list = getjump(fs, list)) {
+    Instruction *i = getjumpcontrol(fs, list);
+    if (GET_OPCODE(*i) == OP_TESTSET)
+      patchtestreg(i, NO_REG);
+  }
+}
+
+
+static void patchlistaux (FuncState *fs, int list, int vtarget, int reg,
+                          int dtarget) {
   while (list != NO_JUMP) {
     int next = getjump(fs, list);
     Instruction *i = getjumpcontrol(fs, list);
-    if (GET_OPCODE(*i) != OP_TEST) {
-      lua_assert(dtarget != NO_JUMP);
-      fixjump(fs, list, dtarget);  /* jump to default target */
-    }
-    else {
-      if (GETARG_C(*i)) {
-        lua_assert(ttarget != NO_JUMP);
-        patchtestreg(i, treg);
-        fixjump(fs, list, ttarget);
-      }
-      else {
-        lua_assert(ftarget != NO_JUMP);
-        patchtestreg(i, freg);
-        fixjump(fs, list, ftarget);
-      }
+    if (GET_OPCODE(*i) == OP_TESTSET) {
+      patchtestreg(i, reg);
+      fixjump(fs, list, vtarget);
     }
+    else
+      fixjump(fs, list, dtarget);  /* jump to default target */
     list = next;
   }
 }
 
 
 static void dischargejpc (FuncState *fs) {
-  patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc, NO_REG, fs->pc);
+  patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc);
   fs->jpc = NO_JUMP;
 }
 
@@ -153,7 +159,7 @@ void luaK_patchlist (FuncState *fs, int list, int target) {
     luaK_patchtohere(fs, list);
   else {
     lua_assert(target < fs->pc);
-    patchlistaux(fs, list, target, NO_REG, target, NO_REG, target);
+    patchlistaux(fs, list, target, NO_REG, target);
   }
 }
 
@@ -373,7 +379,7 @@ static void exp2reg (FuncState *fs, expdesc *e, int reg) {
     int final;  /* position after whole expression */
     int p_f = NO_JUMP;  /* position of an eventual LOAD false */
     int p_t = NO_JUMP;  /* position of an eventual LOAD true */
-    if (need_value(fs, e->t, 1) || need_value(fs, e->f, 0)) {
+    if (need_value(fs, e->t) || need_value(fs, e->f)) {
       int fj = NO_JUMP;  /* first jump (over LOAD ops.) */
       if (e->k != VJMP)
         fj = luaK_jump(fs);
@@ -382,8 +388,8 @@ static void exp2reg (FuncState *fs, expdesc *e, int reg) {
       luaK_patchtohere(fs, fj);
     }
     final = luaK_getlabel(fs);
-    patchlistaux(fs, e->f, p_f, NO_REG, final, reg, p_f);
-    patchlistaux(fs, e->t, final, reg, p_t, NO_REG, p_t);
+    patchlistaux(fs, e->f, final, reg, p_f);
+    patchlistaux(fs, e->t, final, reg, p_t);
   }
   e->f = e->t = NO_JUMP;
   e->info = reg;
@@ -492,7 +498,8 @@ void luaK_self (FuncState *fs, expdesc *e, expdesc *key) {
 
 static void invertjump (FuncState *fs, expdesc *e) {
   Instruction *pc = getjumpcontrol(fs, e->info);
-  lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TEST);
+  lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET &&
+                                           GET_OPCODE(*pc) != OP_TEST);
   SETARG_A(*pc, !(GETARG_A(*pc)));
 }
 
@@ -502,13 +509,13 @@ static int jumponcond (FuncState *fs, expdesc *e, int cond) {
     Instruction ie = getcode(fs, e);
     if (GET_OPCODE(ie) == OP_NOT) {
       fs->pc--;  /* remove previous OP_NOT */
-      return condjump(fs, OP_TEST, NO_REG, GETARG_B(ie), !cond);
+      return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond);
     }
     /* else go through */
   }
   discharge2anyreg(fs, e);
   freeexp(fs, e);
-  return condjump(fs, OP_TEST, NO_REG, e->info, cond);
+  return condjump(fs, OP_TESTSET, NO_REG, e->info, cond);
 }
 
 
@@ -597,6 +604,8 @@ static void codenot (FuncState *fs, expdesc *e) {
   }
   /* interchange true and false lists */
   { int temp = e->f; e->f = e->t; e->t = temp; }
+  removevalues(fs, e->f);
+  removevalues(fs, e->t);
 }
 
 

+ 2 - 1
lcode.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lcode.h,v 1.43 2005/04/25 19:24:10 roberto Exp roberto $
+** $Id: lcode.h,v 1.44 2005/05/20 15:53:42 roberto Exp $
 ** Code generator for Lua
 ** See Copyright Notice in lua.h
 */
@@ -65,6 +65,7 @@ LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e);
 LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults);
 LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e);
 LUAI_FUNC int luaK_jump (FuncState *fs);
+LUAI_FUNC void luaK_ret (FuncState *fs, int first, int nret);
 LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target);
 LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list);
 LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2);

+ 4 - 2
lopcodes.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lopcodes.c,v 1.33 2005/05/04 20:42:28 roberto Exp roberto $
+** $Id: lopcodes.c,v 1.34 2005/05/20 15:53:42 roberto Exp $
 ** See Copyright Notice in lua.h
 */
 
@@ -43,6 +43,7 @@ const char *const luaP_opnames[NUM_OPCODES+1] = {
   "LT",
   "LE",
   "TEST",
+  "TESTSET",
   "CALL",
   "TAILCALL",
   "RETURN",
@@ -87,7 +88,8 @@ const lu_byte luaP_opmodes[NUM_OPCODES] = {
  ,opmode(1, 0, OpArgK, OpArgK, iABC)		/* OP_EQ */
  ,opmode(1, 0, OpArgK, OpArgK, iABC)		/* OP_LT */
  ,opmode(1, 0, OpArgK, OpArgK, iABC)		/* OP_LE */
- ,opmode(1, 1, OpArgR, OpArgU, iABC)		/* OP_TEST */
+ ,opmode(1, 0, OpArgR, OpArgU, iABC)		/* OP_TEST */
+ ,opmode(1, 1, OpArgR, OpArgU, iABC)		/* OP_TESTSET */
  ,opmode(0, 1, OpArgU, OpArgU, iABC)		/* OP_CALL */
  ,opmode(0, 1, OpArgU, OpArgU, iABC)		/* OP_TAILCALL */
  ,opmode(0, 0, OpArgU, OpArgN, iABC)		/* OP_RETURN */

+ 3 - 2
lopcodes.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lopcodes.h,v 1.120 2005/05/20 15:53:42 roberto Exp roberto $
+** $Id: lopcodes.h,v 1.121 2005/06/06 13:30:25 roberto Exp $
 ** Opcodes for Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -186,7 +186,8 @@ OP_EQ,/*	A B C	if ((RK(B) == RK(C)) ~= A) then pc++		*/
 OP_LT,/*	A B C	if ((RK(B) <  RK(C)) ~= A) then pc++  		*/
 OP_LE,/*	A B C	if ((RK(B) <= RK(C)) ~= A) then pc++  		*/
 
-OP_TEST,/*	A B C	if (R(B) <=> C) then R(A) := R(B) else pc++	*/ 
+OP_TEST,/*	A C	if not (R(A) <=> C) then pc++			*/ 
+OP_TESTSET,/*	A B C	if (R(B) <=> C) then R(A) := R(B) else pc++	*/ 
 
 OP_CALL,/*	A B C	R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */
 OP_TAILCALL,/*	A B C	return R(A)(R(A+1), ... ,R(A+B-1))		*/

+ 3 - 4
lparser.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lparser.c,v 2.33 2005/08/22 18:54:32 roberto Exp roberto $
+** $Id: lparser.c,v 2.34 2005/08/24 17:41:10 roberto Exp $
 ** Lua Parser
 ** See Copyright Notice in lua.h
 */
@@ -375,7 +375,7 @@ static void close_func (LexState *ls) {
   FuncState *fs = ls->fs;
   Proto *f = fs->f;
   removevars(ls, 0);
-  luaK_codeABC(fs, OP_RETURN, 0, 1, 0);  /* final return */
+  luaK_ret(fs, 0, 0);  /* final return */
   luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction);
   f->sizecode = fs->pc;
   luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int);
@@ -981,7 +981,6 @@ static int cond (LexState *ls) {
   expdesc v;
   expr(ls, &v);  /* read condition */
   if (v.k == VNIL) v.k = VFALSE;  /* `falses' are all equal here */
-  else if (v.k == VK) v.k = VTRUE;  /* 'trues' too */
   luaK_goiftrue(ls->fs, &v);
   return v.f;
 }
@@ -1279,7 +1278,7 @@ static void retstat (LexState *ls) {
       }
     }
   }
-  luaK_codeABC(fs, OP_RETURN, first, nret+1, 0);
+  luaK_ret(fs, first, nret);
 }
 
 

+ 7 - 1
lvm.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lvm.c,v 2.52 2005/08/22 18:54:49 roberto Exp roberto $
+** $Id: lvm.c,v 2.53 2005/08/24 16:15:49 roberto Exp $
 ** Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -592,6 +592,12 @@ void luaV_execute (lua_State *L, int nexeccalls) {
         continue;
       }
       case OP_TEST: {
+        if (l_isfalse(ra) == GETARG_C(i)) pc++;
+        else
+          dojump(L, pc, GETARG_sBx(*pc) + 1);
+        continue;
+      }
+      case OP_TESTSET: {
         TValue *rb = RB(i);
         if (l_isfalse(rb) == GETARG_C(i)) pc++;
         else {