فهرست منبع

cleaner semantics for test instructions (skips)

Roberto Ierusalimschy 23 سال پیش
والد
کامیت
7ab7703b53
5فایلهای تغییر یافته به همراه48 افزوده شده و 72 حذف شده
  1. 13 10
      lcode.c
  2. 3 4
      ldebug.c
  3. 1 3
      lopcodes.c
  4. 11 15
      lopcodes.h
  5. 20 40
      lvm.c

+ 13 - 10
lcode.c

@@ -71,7 +71,7 @@ int luaK_jump (FuncState *fs) {
 
 static int luaK_condjump (FuncState *fs, OpCode op, int A, int B, int C) {
   luaK_codeABC(fs, op, A, B, C);
-  return luaK_codeAsBc(fs, OP_CJMP, 0, NO_JUMP);
+  return luaK_codeAsBc(fs, OP_JMP, 0, NO_JUMP);
 }
 
 
@@ -127,12 +127,11 @@ static int luaK_getjump (FuncState *fs, int pc) {
 static Instruction *getjumpcontrol (FuncState *fs, int pc) {
   Instruction *pi = &fs->f->code[pc];
   OpCode op = GET_OPCODE(*pi);
-  if (op == OP_CJMP)
+  lua_assert(op == OP_JMP || op == OP_FORLOOP || op == OP_TFORLOOP);
+  if (pc >= 1 && testOpMode(GET_OPCODE(*(pi-1)), OpModeT))
     return pi-1;
-  else {
-    lua_assert(op == OP_JMP || op == OP_FORLOOP || op == OP_TFORLOOP);
+  else
     return pi;
-  }
 }
 
 
@@ -312,18 +311,23 @@ static int code_label (FuncState *fs, int A, int b, int jump) {
 
 
 static void dischargejumps (FuncState *fs, expdesc *e, int reg) {
-  if (hasjumps(e)) {
+  if (e->k == VJMP || hasjumps(e)) {
     int final;  /* position after whole expression */
     int p_f = NO_JUMP;  /* position of an eventual PUSH false */
     int p_t = NO_JUMP;  /* position of an eventual PUSH true */
-    if (need_value(fs, e->f, OP_TESTF) || need_value(fs, e->t, OP_TESTT)) {
+    if (e->k == VJMP || need_value(fs, e->f, OP_TESTF) ||
+                        need_value(fs, e->t, OP_TESTT)) {
       /* expression needs values */
       if (e->k != VJMP) {
         luaK_getlabel(fs);  /* these instruction may be jump target */
         luaK_codeAsBc(fs, OP_JMP, 0, 2);  /* to jump over both pushes */
       }
-      p_f = code_label(fs, reg, 0, 1);
-      p_t = code_label(fs, reg, 1, 0);
+      else {  /* last expression is a conditional (test + jump) */
+        fs->pc--;  /* remove its jump */
+        lua_assert(testOpMode(GET_OPCODE(fs->f->code[fs->pc - 1]), OpModeT));
+      }
+      p_t = code_label(fs, reg, 1, 1);
+      p_f = code_label(fs, reg, 0, 0);
     }
     final = luaK_getlabel(fs);
     luaK_patchlistaux(fs, e->f, p_f, NO_REG, final, reg, p_f);
@@ -389,7 +393,6 @@ static void luaK_exp2reg (FuncState *fs, expdesc *e, int reg) {
       break;
     }
     case VJMP: {
-      luaK_concat(fs, &e->t, e->u.i.info);  /* put this jump in `t' list */
       break;
     }
     default: {

+ 3 - 4
ldebug.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ldebug.c,v 1.96 2001/12/18 20:52:30 roberto Exp $
+** $Id: ldebug.c,v 1.97 2002/01/09 22:02:47 roberto Exp $
 ** Debug Interface
 ** See Copyright Notice in lua.h
 */
@@ -350,7 +350,7 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) {
       if (a == reg) last = pc;  /* change register `a' */
     }
     if (testOpMode(op, OpModeT))
-      check(GET_OPCODE(pt->code[pc+1]) == OP_CJMP);
+      check(pc+2 < pt->sizecode);  /* check skip */
     switch (op) {
       case OP_LOADBOOL: {
         check(c == 0 || pc+2 < pt->sizecode);  /* check its jump */
@@ -381,8 +381,7 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) {
         check(c < MAXSTACK && b < c);
         break;
       }
-      case OP_JMP:
-      case OP_CJMP: {
+      case OP_JMP: {
         int dest = pc+1+b;
 	check(0 <= dest && dest < pt->sizecode);
         /* not full check and jump is forward and do not skip `lastpc'? */

+ 1 - 3
lopcodes.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lopcodes.c,v 1.1 2001/11/29 22:14:34 rieru Exp rieru $
+** $Id: lopcodes.c,v 1.8 2001/12/11 22:48:44 roberto Exp $
 ** extracted automatically from lopcodes.h by mkprint.lua
 ** DO NOT EDIT
 ** See Copyright Notice in lua.h
@@ -37,7 +37,6 @@ const char *const luaP_opnames[] = {
   "NOT",
   "CONCAT",
   "JMP",
-  "CJMP",
   "TESTEQ",
   "TESTNE",
   "TESTLT",
@@ -88,7 +87,6 @@ const lu_byte luaP_opmodes[NUM_OPCODES] = {
  ,opmode(0,0,1,0, 1,0,iABC)		/* OP_NOT */
  ,opmode(0,0,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,0,1, 0,0,iABC)		/* OP_TESTEQ */
  ,opmode(1,0,0,1, 0,0,iABC)		/* OP_TESTNE */
  ,opmode(1,0,0,1, 0,0,iABC)		/* OP_TESTLT */

+ 11 - 15
lopcodes.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lopcodes.h,v 1.1 2001/11/29 22:14:34 rieru Exp rieru $
+** $Id: lopcodes.h,v 1.85 2002/01/09 22:02:47 roberto Exp $
 ** Opcodes for Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -156,17 +156,16 @@ OP_NOT,/*	A B	R(A) := not R(B)				*/
 OP_CONCAT,/*	A B C	R(A) := R(B).. ... ..R(C)			*/
 
 OP_JMP,/*	sBc	PC += sBc					*/
-OP_CJMP,/*	sBc	if test then PC += sBc		(see (1))	*/
 
-OP_TESTEQ,/*	A C	test := (R(A) == R/K(C))			*/
-OP_TESTNE,/*	A C	test := (R(A) ~= R/K(C))			*/
-OP_TESTLT,/*	A C	test := (R(A) < R/K(C))				*/
-OP_TESTLE,/*	A C	test := (R(A) <= R/K(C))			*/
-OP_TESTGT,/*	A C	test := (R(A) > R/K(C))				*/
-OP_TESTGE,/*	A C	test := (R(A) >= R/K(C))			*/
+OP_TESTEQ,/*	A C	if not (R(A) == R/K(C)) then pc++		*/
+OP_TESTNE,/*	A C	if not (R(A) ~= R/K(C)) then pc++		*/
+OP_TESTLT,/*	A C	if not (R(A) < R/K(C)) then pc++		*/
+OP_TESTLE,/*	A C	if not (R(A) <= R/K(C)) then pc++		*/
+OP_TESTGT,/*	A C	if not (R(A) > R/K(C)) then pc++		*/
+OP_TESTGE,/*	A C	if not (R(A) >= R/K(C)) then pc++		*/
 
-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) := R(B)	*/
+OP_TESTT,/*	A B	if (R(B)) then R(A) := R(B) else pc++		*/ 
+OP_TESTF,/*	A B	if not (R(B)) 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_RETURN,/*	A B	return R(A), ... ,R(A+B-2)	(see (3))	*/
@@ -194,14 +193,11 @@ pseudo-instructions (interruptions): cannot occur in regular code
 
 /*===========================================================================
   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 == 0) then B = top. C is the number of returns - 1,
+  (1) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1,
       and can be 0: OP_CALL then sets `top' to last_result+1, so
       next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use `top'.
 
-  (3) In OP_RETURN, if (B == 0) then return up to `top'
+  (2) In OP_RETURN, if (B == 0) then return up to `top'
 ===========================================================================*/
 
 

+ 20 - 40
lvm.c

@@ -64,7 +64,7 @@ int luaV_tostring (lua_State *L, TObject *obj) {
 static void traceexec (lua_State *L, lua_Hook linehook) {
   CallInfo *ci = L->ci;
   int *lineinfo = ci_func(ci)->l.p->lineinfo;
-  int pc = (int)(*ci->pc - ci_func(ci)->l.p->code) - 1;
+  int pc = cast(int, *ci->pc - ci_func(ci)->l.p->code) - 1;
   int newline;
   if (pc == 0) {  /* may be first time? */
     ci->line = 1;
@@ -221,9 +221,10 @@ int luaV_lessthan (lua_State *L, const TObject *l, const TObject *r) {
 }
 
 
-void luaV_strconc (lua_State *L, int total, StkId top) {
-  luaV_checkGC(L, top);
+void luaV_strconc (lua_State *L, int total, int last) {
+  luaV_checkGC(L, L->ci->base + last + 1);
   do {
+    StkId top = L->ci->base + last + 1;
     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))
@@ -249,7 +250,7 @@ void luaV_strconc (lua_State *L, int total, StkId top) {
       setsvalue(top-n, luaS_newlstr(L, buffer, tl));
     }
     total -= n-1;  /* got `n' strings to create 1 new */
-    top -= n-1;
+    last -= n-1;
   } while (total > 1);  /* repeat until only 1 result left */
 }
 
@@ -431,71 +432,50 @@ StkId luaV_execute (lua_State *L) {
         break;
       }
       case OP_CONCAT: {
-        StkId top = RC(i)+1;
-        StkId rb = RB(i);
-        luaV_strconc(L, top-rb, top);
-        setobj(ra, rb);
+        int b = GETARG_B(i);
+        int c = GETARG_C(i);
+        luaV_strconc(L, c-b+1, c);
+        setobj(ra, base+b);
         break;
       }
-      case OP_CJMP:
       case OP_JMP: {
         dojump(pc, i);
         break;
       }
-      case OP_TESTEQ: {
-        lua_assert(GET_OPCODE(*pc) == OP_CJMP);
-        if (luaO_equalObj(ra, RKC(i))) dojump(pc, *pc);
-        pc++;
+      case OP_TESTEQ: {  /* skip next instruction if test fails */
+        if (!luaO_equalObj(ra, RKC(i))) pc++;
         break;
       }
       case OP_TESTNE: {
-        lua_assert(GET_OPCODE(*pc) == OP_CJMP);
-        if (!luaO_equalObj(ra, RKC(i))) dojump(pc, *pc);
-        pc++;
+        if (luaO_equalObj(ra, RKC(i))) pc++;
         break;
       }
       case OP_TESTLT: {
-        lua_assert(GET_OPCODE(*pc) == OP_CJMP);
-        if (luaV_lessthan(L, ra, RKC(i))) dojump(pc, *pc);
-        pc++;
+        if (!luaV_lessthan(L, ra, RKC(i))) pc++;
         break;
       }
       case OP_TESTLE: {  /* b <= c  ===  !(c<b) */
-        lua_assert(GET_OPCODE(*pc) == OP_CJMP);
-        if (!luaV_lessthan(L, RKC(i), ra)) dojump(pc, *pc);
-        pc++;
+        if (luaV_lessthan(L, RKC(i), ra)) pc++;
         break;
       }
       case OP_TESTGT: {  /* b > c  ===  (c<b) */
-        lua_assert(GET_OPCODE(*pc) == OP_CJMP);
-        if (luaV_lessthan(L, RKC(i), ra)) dojump(pc, *pc);
-        pc++;
+        if (!luaV_lessthan(L, RKC(i), ra)) pc++;
         break;
       }
       case OP_TESTGE: {  /* b >= c  === !(b<c) */
-        lua_assert(GET_OPCODE(*pc) == OP_CJMP);
-        if (!luaV_lessthan(L, ra, RKC(i))) dojump(pc, *pc);
-        pc++;
+        if (luaV_lessthan(L, ra, RKC(i))) pc++;
         break;
       }
       case OP_TESTT: {
         StkId rb = RB(i);
-        lua_assert(GET_OPCODE(*pc) == OP_CJMP);
-        if (!l_isfalse(rb)) {
-          setobj(ra, rb);
-          dojump(pc, *pc);
-        }
-        pc++;
+        if (l_isfalse(rb)) pc++;
+        else setobj(ra, rb);
         break;
       }
       case OP_TESTF: {
         StkId rb = RB(i);
-        lua_assert(GET_OPCODE(*pc) == OP_CJMP);
-        if (l_isfalse(rb)) {
-          setobj(ra, rb);
-          dojump(pc, *pc);
-        }
-        pc++;
+        if (!l_isfalse(rb)) pc++;
+        else setobj(ra, rb);
         break;
       }
       case OP_CALL: {