mirror of
https://github.com/lua/lua.git
synced 2025-01-14 05:43:00 +08:00
cleaner implementation of code generation for jumps
This commit is contained in:
parent
b487975344
commit
2dadc81822
65
lcode.c
65
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
|
** Code generator for Lua
|
||||||
** See Copyright Notice in lua.h
|
** 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 luaK_jump (FuncState *fs) {
|
||||||
int j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP);
|
int jpc = fs->jpc; /* save list of jumps to here */
|
||||||
if (j == fs->lasttarget) { /* possible jumps to this jump? */
|
int j;
|
||||||
luaK_concat(fs, &j, fs->jlt); /* keep them on hold */
|
fs->jpc = NO_JUMP;
|
||||||
fs->jlt = NO_JUMP;
|
j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP);
|
||||||
}
|
luaK_concat(fs, &j, jpc); /* keep them on hold */
|
||||||
return j;
|
return j;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int luaK_condjump (FuncState *fs, OpCode op, int A, int B, int C) {
|
static int luaK_condjump (FuncState *fs, OpCode op, int A, int B, int C) {
|
||||||
luaK_codeABC(fs, op, A, B, 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) {
|
static void luaK_fixjump (FuncState *fs, int pc, int dest) {
|
||||||
Instruction *jmp = &fs->f->code[pc];
|
Instruction *jmp = &fs->f->code[pc];
|
||||||
if (dest == NO_JUMP)
|
int offset = dest-(pc+1);
|
||||||
SETARG_sBx(*jmp, NO_JUMP); /* point to itself to represent end of list */
|
lua_assert(dest != NO_JUMP);
|
||||||
else { /* jump is relative to position following jump instruction */
|
if (abs(offset) > MAXARG_sBx)
|
||||||
int offset = dest-(pc+1);
|
luaX_syntaxerror(fs->ls, "control structure too long");
|
||||||
if (abs(offset) > MAXARG_sBx)
|
SETARG_sBx(*jmp, offset);
|
||||||
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
|
** returns current `pc' and marks it as a jump target (to avoid wrong
|
||||||
** optimizations with consecutive instructions not in the same basic block).
|
** optimizations with consecutive instructions not in the same basic block).
|
||||||
** discharge list of jumps to last target.
|
|
||||||
*/
|
*/
|
||||||
int luaK_getlabel (FuncState *fs) {
|
int luaK_getlabel (FuncState *fs) {
|
||||||
if (fs->pc != fs->lasttarget) {
|
fs->lasttarget = fs->pc;
|
||||||
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) */
|
|
||||||
}
|
|
||||||
return 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) {
|
static int luaK_getjump (FuncState *fs, int pc) {
|
||||||
int offset = GETARG_sBx(fs->f->code[pc]);
|
int offset = GETARG_sBx(fs->f->code[pc]);
|
||||||
if (offset == NO_JUMP) /* point to itself represents end of list */
|
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) {
|
void luaK_patchlist (FuncState *fs, int list, int target) {
|
||||||
if (target == fs->lasttarget) /* same target that list `jlt'? */
|
lua_assert(target <= fs->pc);
|
||||||
luaK_concat(fs, &fs->jlt, list); /* delay fixing */
|
luaK_patchlistaux(fs, list, target, NO_REG, target, NO_REG, target);
|
||||||
else
|
|
||||||
luaK_patchlistaux(fs, list, target, NO_REG, target, NO_REG, target);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void luaK_patchtohere (FuncState *fs, int list) {
|
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) {
|
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;
|
*l1 = l2;
|
||||||
else {
|
else {
|
||||||
int list = *l1;
|
int list = *l1;
|
||||||
@ -508,7 +498,7 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case VFALSE: {
|
case VFALSE: {
|
||||||
pc = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP); /* always jump */
|
pc = luaK_jump(fs); /* always jump */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case VJMP: {
|
case VJMP: {
|
||||||
@ -534,7 +524,7 @@ void luaK_goiffalse (FuncState *fs, expdesc *e) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case VTRUE: {
|
case VTRUE: {
|
||||||
pc = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP); /* always jump */
|
pc = luaK_jump(fs); /* always jump */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case VJMP: {
|
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) {
|
int luaK_code (FuncState *fs, Instruction i, int line) {
|
||||||
Proto *f = fs->f;
|
Proto *f = fs->f;
|
||||||
int oldsize = f->sizecode;
|
int oldsize = f->sizecode;
|
||||||
|
luaK_dischargejpc(fs); /* `pc' will change */
|
||||||
/* put new instruction in code array */
|
/* put new instruction in code array */
|
||||||
luaM_growvector(fs->L, f->code, fs->pc, f->sizecode, Instruction,
|
luaM_growvector(fs->L, f->code, fs->pc, f->sizecode, Instruction,
|
||||||
MAX_INT, "code size overflow");
|
MAX_INT, "code size overflow");
|
||||||
|
4
lcode.h
4
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
|
** Code generator for Lua
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@ -55,12 +55,12 @@ void luaK_exp2val (FuncState *fs, expdesc *e);
|
|||||||
int luaK_exp2RK (FuncState *fs, expdesc *e);
|
int luaK_exp2RK (FuncState *fs, expdesc *e);
|
||||||
void luaK_self (FuncState *fs, expdesc *e, expdesc *key);
|
void luaK_self (FuncState *fs, expdesc *e, expdesc *key);
|
||||||
void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k);
|
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_goiftrue (FuncState *fs, expdesc *e);
|
||||||
void luaK_goiffalse (FuncState *fs, expdesc *e);
|
void luaK_goiffalse (FuncState *fs, expdesc *e);
|
||||||
void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e);
|
void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e);
|
||||||
void luaK_setcallreturns (FuncState *fs, expdesc *var, int nresults);
|
void luaK_setcallreturns (FuncState *fs, expdesc *var, int nresults);
|
||||||
int luaK_jump (FuncState *fs);
|
int luaK_jump (FuncState *fs);
|
||||||
|
void luaK_dischargejpc (FuncState *fs);
|
||||||
void luaK_patchlist (FuncState *fs, int list, int target);
|
void luaK_patchlist (FuncState *fs, int list, int target);
|
||||||
void luaK_patchtohere (FuncState *fs, int list);
|
void luaK_patchtohere (FuncState *fs, int list);
|
||||||
void luaK_concat (FuncState *fs, int *l1, int l2);
|
void luaK_concat (FuncState *fs, int *l1, int l2);
|
||||||
|
26
lparser.c
26
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
|
** Lua Parser
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@ -367,7 +367,7 @@ static void open_func (LexState *ls, FuncState *fs) {
|
|||||||
ls->fs = fs;
|
ls->fs = fs;
|
||||||
fs->pc = 0;
|
fs->pc = 0;
|
||||||
fs->lasttarget = 0;
|
fs->lasttarget = 0;
|
||||||
fs->jlt = NO_JUMP;
|
fs->jpc = NO_JUMP;
|
||||||
fs->freereg = 0;
|
fs->freereg = 0;
|
||||||
fs->nk = 0;
|
fs->nk = 0;
|
||||||
fs->h = luaH_new(ls->L, 0, 0);
|
fs->h = luaH_new(ls->L, 0, 0);
|
||||||
@ -391,7 +391,6 @@ static void close_func (LexState *ls) {
|
|||||||
Proto *f = fs->f;
|
Proto *f = fs->f;
|
||||||
removevars(ls, 0);
|
removevars(ls, 0);
|
||||||
luaK_codeABC(fs, OP_RETURN, 0, 1, 0); /* final return */
|
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);
|
lua_assert(G(L)->roottable == fs->h);
|
||||||
G(L)->roottable = fs->h->next;
|
G(L)->roottable = fs->h->next;
|
||||||
luaH_free(L, fs->h);
|
luaH_free(L, fs->h);
|
||||||
@ -977,30 +976,33 @@ static void whilestat (LexState *ls, int line) {
|
|||||||
int i;
|
int i;
|
||||||
int sizeexp;
|
int sizeexp;
|
||||||
FuncState *fs = ls->fs;
|
FuncState *fs = ls->fs;
|
||||||
int while_init = luaK_getlabel(fs);
|
int whileinit, blockinit, expinit;
|
||||||
expdesc v;
|
expdesc v;
|
||||||
BlockCnt bl;
|
BlockCnt bl;
|
||||||
next(ls);
|
next(ls);
|
||||||
|
whileinit = luaK_jump(fs);
|
||||||
|
expinit = luaK_getlabel(fs);
|
||||||
expr(ls, &v);
|
expr(ls, &v);
|
||||||
if (v.k == VK) v.k = VTRUE; /* `trues' are all equal here */
|
if (v.k == VK) v.k = VTRUE; /* `trues' are all equal here */
|
||||||
lineexp = ls->linenumber;
|
lineexp = ls->linenumber;
|
||||||
luaK_goiffalse(fs, &v);
|
luaK_goiffalse(fs, &v);
|
||||||
sizeexp = fs->pc - while_init;
|
luaK_dischargejpc(fs);
|
||||||
|
sizeexp = fs->pc - expinit;
|
||||||
if (sizeexp > MAXEXPWHILE)
|
if (sizeexp > MAXEXPWHILE)
|
||||||
luaX_syntaxerror(ls, "while condition too complex");
|
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 */
|
for (i = 0; i < sizeexp; i++) /* save `exp' code */
|
||||||
codeexp[i] = fs->f->code[while_init + i];
|
codeexp[i] = fs->f->code[expinit + i];
|
||||||
luaK_jump(fs);
|
fs->pc = expinit; /* remove `exp' code */
|
||||||
enterblock(fs, &bl, 1);
|
enterblock(fs, &bl, 1);
|
||||||
check(ls, TK_DO);
|
check(ls, TK_DO);
|
||||||
|
blockinit = luaK_getlabel(fs);
|
||||||
block(ls);
|
block(ls);
|
||||||
luaK_patchtohere(fs, while_init); /* initial jump jumps to here */
|
luaK_patchtohere(fs, whileinit); /* initial jump jumps to here */
|
||||||
luaK_moveexp(&v, fs->pc - while_init); /* correct pointers */
|
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++)
|
for (i=0; i<sizeexp; i++)
|
||||||
luaK_code(fs, codeexp[i], lineexp);
|
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);
|
luaK_patchtohere(fs, v.f);
|
||||||
check_match(ls, TK_END, TK_WHILE, line);
|
check_match(ls, TK_END, TK_WHILE, line);
|
||||||
leaveblock(fs);
|
leaveblock(fs);
|
||||||
|
@ -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
|
** Lua Parser
|
||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
@ -63,7 +63,7 @@ typedef struct FuncState {
|
|||||||
struct BlockCnt *bl; /* chain of current blocks */
|
struct BlockCnt *bl; /* chain of current blocks */
|
||||||
int pc; /* next position to code (equivalent to `ncode') */
|
int pc; /* next position to code (equivalent to `ncode') */
|
||||||
int lasttarget; /* `pc' of last `jump target' */
|
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 freereg; /* first free register */
|
||||||
int defaultglob; /* where to look for non-declared globals */
|
int defaultglob; /* where to look for non-declared globals */
|
||||||
int nk; /* number of elements in `k' */
|
int nk; /* number of elements in `k' */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user