Browse Source

cleaner implementation of code generation for jumps

Roberto Ierusalimschy 23 years ago
parent
commit
2dadc81822
4 changed files with 46 additions and 53 deletions
  1. 28 37
      lcode.c
  2. 2 2
      lcode.h
  3. 14 12
      lparser.c
  4. 2 2
      lparser.h

+ 28 - 37
lcode.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lcode.c,v 1.100 2002/05/09 14:14:34 roberto Exp roberto $
+** $Id: lcode.c,v 1.101 2002/05/10 17:02:32 roberto Exp roberto $
 ** Code generator for Lua
 ** See Copyright Notice in lua.h
 */
@@ -39,58 +39,48 @@ void luaK_nil (FuncState *fs, int from, int n) {
 }
 
 
-void luaK_moveexp (expdesc *e, int offset) {
-  if (e->t != NO_JUMP) e->t += offset;
-  if (e->f != NO_JUMP) e->f += offset;
-  if (e->k == VRELOCABLE || e->k == VJMP) e->info += offset;
-}
-
-
 int luaK_jump (FuncState *fs) {
-  int j = luaK_codeAsBx(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;
-  }
+  int jpc = fs->jpc;  /* save list of jumps to here */
+  int j;
+  fs->jpc = NO_JUMP;
+  j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP);
+  luaK_concat(fs, &j, jpc);  /* keep them on hold */
   return j;
 }
 
 
 static int luaK_condjump (FuncState *fs, OpCode op, int A, int B, int C) {
   luaK_codeABC(fs, op, A, B, C);
-  return luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP);
+  return luaK_jump(fs);
 }
 
 
 static void luaK_fixjump (FuncState *fs, int pc, int dest) {
   Instruction *jmp = &fs->f->code[pc];
-  if (dest == NO_JUMP)
-    SETARG_sBx(*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_sBx)
-      luaX_syntaxerror(fs->ls, "control structure too long");
-    SETARG_sBx(*jmp, offset);
-  }
+  int offset = dest-(pc+1);
+  lua_assert(dest != NO_JUMP);
+  if (abs(offset) > MAXARG_sBx)
+    luaX_syntaxerror(fs->ls, "control structure too long");
+  SETARG_sBx(*jmp, offset);
 }
 
 
 /*
 ** returns current `pc' and marks it as a jump target (to avoid wrong
 ** optimizations with consecutive instructions not in the same basic block).
-** discharge list of jumps to last target.
 */
 int luaK_getlabel (FuncState *fs) {
-  if (fs->pc != fs->lasttarget) {
-    int lasttarget = fs->lasttarget;
-    fs->lasttarget = fs->pc;
-    luaK_patchlist(fs, fs->jlt, lasttarget);  /* discharge old list `jlt' */
-    fs->jlt = NO_JUMP;  /* nobody jumps to this new label (yet) */
-  }
+  fs->lasttarget = fs->pc;
   return fs->pc;
 }
 
 
+void luaK_dischargejpc (FuncState *fs) {
+  luaK_patchlist(fs, fs->jpc, fs->pc);  /* discharge old list `jpc' */
+  fs->jpc = NO_JUMP;
+}
+
+
 static int luaK_getjump (FuncState *fs, int pc) {
   int offset = GETARG_sBx(fs->f->code[pc]);
   if (offset == NO_JUMP)  /* point to itself represents end of list */
@@ -155,20 +145,20 @@ static void luaK_patchlistaux (FuncState *fs, int list,
 
 
 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, NO_REG, target, NO_REG, target);
+  lua_assert(target <= fs->pc);
+  luaK_patchlistaux(fs, list, target, NO_REG, target, NO_REG, target);
 }
 
 
 void luaK_patchtohere (FuncState *fs, int list) {
-  luaK_patchlist(fs, list, luaK_getlabel(fs));
+  luaK_getlabel(fs);
+  luaK_concat(fs, &fs->jpc, list);
 }
 
 
 void luaK_concat (FuncState *fs, int *l1, int l2) {
-  if (*l1 == NO_JUMP)
+  if (l2 == NO_JUMP) return;
+  else if (*l1 == NO_JUMP)
     *l1 = l2;
   else {
     int list = *l1;
@@ -508,7 +498,7 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) {
       break;
     }
     case VFALSE: {
-      pc = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP);  /* always jump */
+      pc = luaK_jump(fs);  /* always jump */
       break;
     }
     case VJMP: {
@@ -534,7 +524,7 @@ void luaK_goiffalse (FuncState *fs, expdesc *e) {
       break;
     }
     case VTRUE: {
-      pc = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP);  /* always jump */
+      pc = luaK_jump(fs);  /* always jump */
       break;
     }
     case VJMP: {
@@ -737,6 +727,7 @@ void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) {
 int luaK_code (FuncState *fs, Instruction i, int line) {
   Proto *f = fs->f;
   int oldsize = f->sizecode;
+  luaK_dischargejpc(fs);  /* `pc' will change */
   /* put new instruction in code array */
   luaM_growvector(fs->L, f->code, fs->pc, f->sizecode, Instruction,
                   MAX_INT, "code size overflow");

+ 2 - 2
lcode.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lcode.h,v 1.33 2002/05/07 17:36:56 roberto Exp roberto $
+** $Id: lcode.h,v 1.34 2002/05/10 17:02:32 roberto Exp roberto $
 ** Code generator for Lua
 ** See Copyright Notice in lua.h
 */
@@ -55,12 +55,12 @@ 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_moveexp (expdesc *e, int offset);
 void luaK_goiftrue (FuncState *fs, expdesc *e);
 void luaK_goiffalse (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_dischargejpc (FuncState *fs);
 void luaK_patchlist (FuncState *fs, int list, int target);
 void luaK_patchtohere (FuncState *fs, int list);
 void luaK_concat (FuncState *fs, int *l1, int l2);

+ 14 - 12
lparser.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lparser.c,v 1.179 2002/05/07 17:36:56 roberto Exp roberto $
+** $Id: lparser.c,v 1.180 2002/05/10 17:02:32 roberto Exp roberto $
 ** Lua Parser
 ** See Copyright Notice in lua.h
 */
@@ -367,7 +367,7 @@ static void open_func (LexState *ls, FuncState *fs) {
   ls->fs = fs;
   fs->pc = 0;
   fs->lasttarget = 0;
-  fs->jlt = NO_JUMP;
+  fs->jpc = NO_JUMP;
   fs->freereg = 0;
   fs->nk = 0;
   fs->h = luaH_new(ls->L, 0, 0);
@@ -391,7 +391,6 @@ static void close_func (LexState *ls) {
   Proto *f = fs->f;
   removevars(ls, 0);
   luaK_codeABC(fs, OP_RETURN, 0, 1, 0);  /* final return */
-  luaK_getlabel(fs);  /* close eventual list of pending jumps */
   lua_assert(G(L)->roottable == fs->h);
   G(L)->roottable = fs->h->next;
   luaH_free(L, fs->h);
@@ -977,30 +976,33 @@ static void whilestat (LexState *ls, int line) {
   int i;
   int sizeexp;
   FuncState *fs = ls->fs;
-  int while_init = luaK_getlabel(fs);
+  int whileinit, blockinit, expinit;
   expdesc v;
   BlockCnt bl;
   next(ls);
+  whileinit = luaK_jump(fs);
+  expinit = luaK_getlabel(fs);
   expr(ls, &v);
   if (v.k == VK) v.k = VTRUE;  /* `trues' are all equal here */
   lineexp = ls->linenumber;
   luaK_goiffalse(fs, &v);
-  sizeexp = fs->pc - while_init;
+  luaK_dischargejpc(fs);
+  sizeexp = fs->pc - expinit;
   if (sizeexp > MAXEXPWHILE) 
     luaX_syntaxerror(ls, "while condition too complex");
-  fs->pc = while_init;  /* remove `exp' code */
-  luaK_getlabel(fs);
   for (i = 0; i < sizeexp; i++)  /* save `exp' code */
-    codeexp[i] = fs->f->code[while_init + i];
-  luaK_jump(fs);
+    codeexp[i] = fs->f->code[expinit + i];
+  fs->pc = expinit;  /* remove `exp' code */
   enterblock(fs, &bl, 1);
   check(ls, TK_DO);
+  blockinit = luaK_getlabel(fs);
   block(ls);
-  luaK_patchtohere(fs, while_init);  /* initial jump jumps to here */
-  luaK_moveexp(&v, fs->pc - while_init);  /* correct pointers */
+  luaK_patchtohere(fs, whileinit);  /* initial jump jumps to here */
+  if (v.t != NO_JUMP) v.t += fs->pc - expinit;
+  if (v.f != NO_JUMP) v.f += fs->pc - expinit;
   for (i=0; i<sizeexp; i++)
     luaK_code(fs, codeexp[i], lineexp);
-  luaK_patchlist(fs, v.t, while_init+1);
+  luaK_patchlist(fs, v.t, blockinit);
   luaK_patchtohere(fs, v.f);
   check_match(ls, TK_END, TK_WHILE, line);
   leaveblock(fs);

+ 2 - 2
lparser.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lparser.h,v 1.41 2002/03/25 17:47:14 roberto Exp roberto $
+** $Id: lparser.h,v 1.42 2002/05/09 18:00:38 roberto Exp roberto $
 ** Lua Parser
 ** See Copyright Notice in lua.h
 */
@@ -63,7 +63,7 @@ typedef struct FuncState {
   struct BlockCnt *bl;  /* chain of current blocks */
   int pc;  /* next position to code (equivalent to `ncode') */
   int lasttarget;   /* `pc' of last `jump target' */
-  int jlt;  /* list of jumps to `lasttarget' */
+  int jpc;  /* list of jumps to `pc' */
   int freereg;  /* first free register */
   int defaultglob;  /* where to look for non-declared globals */
   int nk;  /* number of elements in `k' */