new way to distinguish between indexing tables in registers and

tables in upvalues (+ fixed small bug when checking conflicts in
multiple assignments)
This commit is contained in:
Roberto Ierusalimschy
2010-07-07 13:27:29 -03:00
parent 6a02bbe1e2
commit 81dd13f4c6
3 changed files with 41 additions and 46 deletions

28
lcode.c
View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lcode.c,v 2.47 2010/06/30 14:11:17 roberto Exp roberto $ ** $Id: lcode.c,v 2.48 2010/07/02 20:42:40 roberto Exp roberto $
** Code generator for Lua ** Code generator for Lua
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -373,15 +373,13 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) {
break; break;
} }
case VINDEXED: { case VINDEXED: {
OpCode op = OP_GETTABUP; /* assume 't' is in an upvalue */
freereg(fs, e->u.ind.idx); freereg(fs, e->u.ind.idx);
freereg(fs, e->u.ind.t); if (e->u.ind.vt == VLOCAL) { /* 't' is in a register? */
e->u.info = luaK_codeABC(fs, OP_GETTABLE, 0, e->u.ind.t, e->u.ind.idx); freereg(fs, e->u.ind.t);
e->k = VRELOCABLE; op = OP_GETTABLE;
break; }
} e->u.info = luaK_codeABC(fs, op, 0, e->u.ind.t, e->u.ind.idx);
case VINDEXEDUP: {
freereg(fs, e->u.ind.idx);
e->u.info = luaK_codeABC(fs, OP_GETTABUP, 0, e->u.ind.t, e->u.ind.idx);
e->k = VRELOCABLE; e->k = VRELOCABLE;
break; break;
} }
@@ -551,13 +549,9 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
break; break;
} }
case VINDEXED: { case VINDEXED: {
OpCode op = (var->u.ind.vt == VLOCAL) ? OP_SETTABLE : OP_SETTABUP;
int e = luaK_exp2RK(fs, ex); int e = luaK_exp2RK(fs, ex);
luaK_codeABC(fs, OP_SETTABLE, var->u.ind.t, var->u.ind.idx, e); luaK_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e);
break;
}
case VINDEXEDUP: {
int e = luaK_exp2RK(fs, ex);
luaK_codeABC(fs, OP_SETTABUP, var->u.ind.t, var->u.ind.idx, e);
break; break;
} }
default: { default: {
@@ -705,7 +699,9 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
lua_assert(!hasjumps(t)); lua_assert(!hasjumps(t));
t->u.ind.t = t->u.info; t->u.ind.t = t->u.info;
t->u.ind.idx = luaK_exp2RK(fs, k); t->u.ind.idx = luaK_exp2RK(fs, k);
t->k = (t->k == VUPVAL) ? VINDEXEDUP : VINDEXED; t->u.ind.vt = (t->k == VUPVAL) ? VUPVAL
: check_exp(vkisinreg(t->k), VLOCAL);
t->k = VINDEXED;
} }

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lparser.c,v 2.88 2010/06/21 16:30:12 roberto Exp roberto $ ** $Id: lparser.c,v 2.89 2010/07/02 20:42:40 roberto Exp roberto $
** Lua Parser ** Lua Parser
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -969,26 +969,25 @@ struct LHS_assign {
** local value in a safe place and use this safe copy in the previous ** local value in a safe place and use this safe copy in the previous
** assignment. ** assignment.
*/ */
static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v, static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
expkind ix, OpCode op) {
FuncState *fs = ls->fs; FuncState *fs = ls->fs;
int extra = fs->freereg; /* eventual position to save local variable */ int extra = fs->freereg; /* eventual position to save local variable */
int conflict = 0; int conflict = 0;
for (; lh; lh = lh->prev) { for (; lh; lh = lh->prev) {
if (lh->v.k == ix) { /* conflict in table 't'? */
if (lh->v.u.ind.t == v->u.info) { /* conflict? */ if (lh->v.u.ind.vt == v->k && lh->v.u.ind.t == v->u.info) {
conflict = 1; conflict = 1;
lh->v.k = VINDEXED; lh->v.u.ind.vt = VLOCAL;
lh->v.u.ind.t = extra; /* previous assignment will use safe copy */ lh->v.u.ind.t = extra; /* previous assignment will use safe copy */
} }
if (v->k == VLOCAL && lh->v.u.ind.idx == v->u.info) { /* conflict? */ /* conflict in index 'idx'? */
conflict = 1; if (v->k == VLOCAL && lh->v.u.ind.idx == v->u.info) {
lua_assert(lh->v.k == VINDEXED); conflict = 1;
lh->v.u.ind.idx = extra; /* previous assignment will use safe copy */ lh->v.u.ind.idx = extra; /* previous assignment will use safe copy */
}
} }
} }
if (conflict) { if (conflict) {
OpCode op = (v->k == VLOCAL) ? OP_MOVE : OP_GETUPVAL;
luaK_codeABC(fs, op, fs->freereg, v->u.info, 0); /* make copy */ luaK_codeABC(fs, op, fs->freereg, v->u.info, 0); /* make copy */
luaK_reserveregs(fs, 1); luaK_reserveregs(fs, 1);
} }
@@ -997,16 +996,13 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v,
static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) { static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) {
expdesc e; expdesc e;
check_condition(ls, VLOCAL <= lh->v.k && lh->v.k <= VINDEXEDUP, check_condition(ls, vkisvar(lh->v.k), "syntax error");
"syntax error");
if (testnext(ls, ',')) { /* assignment -> `,' primaryexp assignment */ if (testnext(ls, ',')) { /* assignment -> `,' primaryexp assignment */
struct LHS_assign nv; struct LHS_assign nv;
nv.prev = lh; nv.prev = lh;
primaryexp(ls, &nv.v); primaryexp(ls, &nv.v);
if (nv.v.k == VLOCAL) if (nv.v.k != VINDEXED)
check_conflict(ls, lh, &nv.v, VINDEXED, OP_MOVE); check_conflict(ls, lh, &nv.v);
else if (nv.v.k == VUPVAL)
check_conflict(ls, lh, &nv.v, VINDEXEDUP, OP_GETUPVAL);
checklimit(ls->fs, nvars, LUAI_MAXCCALLS - G(ls->L)->nCcalls, checklimit(ls->fs, nvars, LUAI_MAXCCALLS - G(ls->L)->nCcalls,
"variable names"); "variable names");
assignment(ls, &nv, nvars+1); assignment(ls, &nv, nvars+1);

View File

@@ -1,5 +1,5 @@
/* /*
** $Id: lparser.h,v 1.63 2010/03/12 19:14:06 roberto Exp roberto $ ** $Id: lparser.h,v 1.64 2010/07/02 20:42:40 roberto Exp roberto $
** Lua Parser ** Lua Parser
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@@ -23,27 +23,30 @@ typedef enum {
VFALSE, VFALSE,
VK, /* info = index of constant in `k' */ VK, /* info = index of constant in `k' */
VKNUM, /* nval = numerical value */ VKNUM, /* nval = numerical value */
VNONRELOC, /* info = result register */
VLOCAL, /* info = local register */ VLOCAL, /* info = local register */
VUPVAL, /* info = index of upvalue in 'upvalues' */ VUPVAL, /* info = index of upvalue in 'upvalues' */
VINDEXED, /* t = table register; idx = index R/K */ VINDEXED, /* t = table register/upvalue; idx = index R/K */
VINDEXEDUP, /* t = table upvalue; idx = index R/K */
VJMP, /* info = instruction pc */ VJMP, /* info = instruction pc */
VRELOCABLE, /* info = instruction pc */ VRELOCABLE, /* info = instruction pc */
VNONRELOC, /* info = result register */
VCALL, /* info = instruction pc */ VCALL, /* info = instruction pc */
VVARARG /* info = instruction pc */ VVARARG /* info = instruction pc */
} expkind; } expkind;
#define vkisvar(k) (VLOCAL <= (k) && (k) <= VINDEXED)
#define vkisinreg(k) ((k) == VNONRELOC || (k) == VLOCAL)
typedef struct expdesc { typedef struct expdesc {
expkind k; expkind k;
union { union {
struct { struct { /* for indexed variables (VINDEXED) */
short idx; short idx; /* index (R/K) */
lu_byte t; lu_byte t; /* table (register or upvalue) */
} ind; /* for indexed variables */ lu_byte vt; /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */
int info; } ind;
lua_Number nval; int info; /* for generic use */
lua_Number nval; /* for VKNUM */
} u; } u;
int t; /* patch list of `exit when true' */ int t; /* patch list of `exit when true' */
int f; /* patch list of `exit when false' */ int f; /* patch list of `exit when false' */