From 7ab7703b53be3024a06334653b29dac338e55a01 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Wed, 16 Jan 2002 20:03:57 -0200 Subject: [PATCH] cleaner semantics for test instructions (skips) --- lcode.c | 23 ++++++++++++--------- ldebug.c | 7 +++---- lopcodes.c | 4 +--- lopcodes.h | 26 ++++++++++------------- lvm.c | 60 ++++++++++++++++++------------------------------------ 5 files changed, 48 insertions(+), 72 deletions(-) diff --git a/lcode.c b/lcode.c index a93b52b9..835dc25d 100644 --- a/lcode.c +++ b/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: { diff --git a/ldebug.c b/ldebug.c index 17a0f11a..2edb4860 100644 --- a/ldebug.c +++ b/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'? */ diff --git a/lopcodes.c b/lopcodes.c index e52805e5..e9ae53b5 100644 --- a/lopcodes.c +++ b/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 */ diff --git a/lopcodes.h b/lopcodes.h index 722e3d6a..6e2103c9 100644 --- a/lopcodes.h +++ b/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' ===========================================================================*/ diff --git a/lvm.c b/lvm.c index b1dad7a8..b51ea0e0 100644 --- a/lvm.c +++ b/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 c === (c= c === !(b