aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2019-07-09 10:43:17 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2019-07-09 10:43:17 -0300
commit54f7b46c1e8a0188e1649046a3a72522f2d769f4 (patch)
tree28e973e10e2bc82de4d7d1e7a9f6673b028f7ad2
parente888976bc6ba5592fb8ab8ecc04a8f63e217aa74 (diff)
downloadlua-54f7b46c1e8a0188e1649046a3a72522f2d769f4.tar.gz
lua-54f7b46c1e8a0188e1649046a3a72522f2d769f4.tar.bz2
lua-54f7b46c1e8a0188e1649046a3a72522f2d769f4.zip
New implementation for constants
VLOCAL expressions keep a reference to their corresponding 'Vardesc', and 'Upvaldesc' (for upvalues) has a field 'ro' (read-only). So, it is easier to check whether a variable is read-only. The decoupling in VLOCAL between 'vidx' ('Vardesc' index) and 'sidx' (stack index) should also help the forthcoming implementation of compile-time constant propagation.
-rw-r--r--lcode.c60
-rw-r--r--lcode.h1
-rw-r--r--ldump.c1
-rw-r--r--lobject.h1
-rw-r--r--lparser.c158
-rw-r--r--lparser.h16
-rw-r--r--lundump.c1
-rw-r--r--testes/locals.lua18
8 files changed, 125 insertions, 131 deletions
diff --git a/lcode.c b/lcode.c
index 1005f1b7..cb6ea0dc 100644
--- a/lcode.c
+++ b/lcode.c
@@ -52,7 +52,7 @@ l_noret luaK_semerror (LexState *ls, const char *msg) {
52** If expression is a numeric constant, fills 'v' with its value 52** If expression is a numeric constant, fills 'v' with its value
53** and returns 1. Otherwise, returns 0. 53** and returns 1. Otherwise, returns 0.
54*/ 54*/
55int luaK_tonumeral (FuncState *fs, const expdesc *e, TValue *v) { 55static int tonumeral (const expdesc *e, TValue *v) {
56 if (hasjumps(e)) 56 if (hasjumps(e))
57 return 0; /* not a numeral */ 57 return 0; /* not a numeral */
58 switch (e->k) { 58 switch (e->k) {
@@ -62,42 +62,12 @@ int luaK_tonumeral (FuncState *fs, const expdesc *e, TValue *v) {
62 case VKFLT: 62 case VKFLT:
63 if (v) setfltvalue(v, e->u.nval); 63 if (v) setfltvalue(v, e->u.nval);
64 return 1; 64 return 1;
65 case VUPVAL: { /* may be a constant */
66 Vardesc *vd = luaY_getvardesc(&fs, e);
67 if (v && vd && !ttisnil(&vd->val)) {
68 setobj(fs->ls->L, v, &vd->val);
69 return 1;
70 } /* else */
71 } /* FALLTHROUGH */
72 default: return 0; 65 default: return 0;
73 } 66 }
74} 67}
75 68
76 69
77/* 70/*
78** If expression 'e' is a constant, change 'e' to represent
79** the constant value.
80*/
81static int const2exp (FuncState *fs, expdesc *e) {
82 Vardesc *vd = luaY_getvardesc(&fs, e);
83 if (vd) {
84 TValue *v = &vd->val;
85 switch (ttypetag(v)) {
86 case LUA_TNUMINT:
87 e->k = VKINT;
88 e->u.ival = ivalue(v);
89 return 1;
90 case LUA_TNUMFLT:
91 e->k = VKFLT;
92 e->u.nval = fltvalue(v);
93 return 1;
94 }
95 }
96 return 0;
97}
98
99
100/*
101** Return the previous instruction of the current code. If there 71** Return the previous instruction of the current code. If there
102** may be a jump target between the current instruction and the 72** may be a jump target between the current instruction and the
103** previous one, return an invalid instruction (to avoid wrong 73** previous one, return an invalid instruction (to avoid wrong
@@ -708,15 +678,13 @@ void luaK_setoneret (FuncState *fs, expdesc *e) {
708void luaK_dischargevars (FuncState *fs, expdesc *e) { 678void luaK_dischargevars (FuncState *fs, expdesc *e) {
709 switch (e->k) { 679 switch (e->k) {
710 case VLOCAL: { /* already in a register */ 680 case VLOCAL: { /* already in a register */
711 e->u.info = e->u.var.idx; 681 e->u.info = e->u.var.sidx;
712 e->k = VNONRELOC; /* becomes a non-relocatable value */ 682 e->k = VNONRELOC; /* becomes a non-relocatable value */
713 break; 683 break;
714 } 684 }
715 case VUPVAL: { /* move value to some (pending) register */ 685 case VUPVAL: { /* move value to some (pending) register */
716 if (!const2exp(fs, e)) { 686 e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0);
717 e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.var.idx, 0); 687 e->k = VRELOC;
718 e->k = VRELOC;
719 }
720 break; 688 break;
721 } 689 }
722 case VINDEXUP: { 690 case VINDEXUP: {
@@ -971,12 +939,12 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
971 switch (var->k) { 939 switch (var->k) {
972 case VLOCAL: { 940 case VLOCAL: {
973 freeexp(fs, ex); 941 freeexp(fs, ex);
974 exp2reg(fs, ex, var->u.var.idx); /* compute 'ex' into proper place */ 942 exp2reg(fs, ex, var->u.var.sidx); /* compute 'ex' into proper place */
975 return; 943 return;
976 } 944 }
977 case VUPVAL: { 945 case VUPVAL: {
978 int e = luaK_exp2anyreg(fs, ex); 946 int e = luaK_exp2anyreg(fs, ex);
979 luaK_codeABC(fs, OP_SETUPVAL, e, var->u.var.idx, 0); 947 luaK_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0);
980 break; 948 break;
981 } 949 }
982 case VINDEXUP: { 950 case VINDEXUP: {
@@ -1203,13 +1171,13 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
1203 if (t->k == VUPVAL && !isKstr(fs, k)) /* upvalue indexed by non string? */ 1171 if (t->k == VUPVAL && !isKstr(fs, k)) /* upvalue indexed by non string? */
1204 luaK_exp2anyreg(fs, t); /* put it in a register */ 1172 luaK_exp2anyreg(fs, t); /* put it in a register */
1205 if (t->k == VUPVAL) { 1173 if (t->k == VUPVAL) {
1206 t->u.ind.t = t->u.var.idx; /* upvalue index */ 1174 t->u.ind.t = t->u.info; /* upvalue index */
1207 t->u.ind.idx = k->u.info; /* literal string */ 1175 t->u.ind.idx = k->u.info; /* literal string */
1208 t->k = VINDEXUP; 1176 t->k = VINDEXUP;
1209 } 1177 }
1210 else { 1178 else {
1211 /* register index of the table */ 1179 /* register index of the table */
1212 t->u.ind.t = (t->k == VLOCAL) ? t->u.var.idx: t->u.info; 1180 t->u.ind.t = (t->k == VLOCAL) ? t->u.var.sidx: t->u.info;
1213 if (isKstr(fs, k)) { 1181 if (isKstr(fs, k)) {
1214 t->u.ind.idx = k->u.info; /* literal string */ 1182 t->u.ind.idx = k->u.info; /* literal string */
1215 t->k = VINDEXSTR; 1183 t->k = VINDEXSTR;
@@ -1252,9 +1220,7 @@ static int validop (int op, TValue *v1, TValue *v2) {
1252static int constfolding (FuncState *fs, int op, expdesc *e1, 1220static int constfolding (FuncState *fs, int op, expdesc *e1,
1253 const expdesc *e2) { 1221 const expdesc *e2) {
1254 TValue v1, v2, res; 1222 TValue v1, v2, res;
1255 if (!luaK_tonumeral(fs, e1, &v1) || 1223 if (!tonumeral(e1, &v1) || !tonumeral(e2, &v2) || !validop(op, &v1, &v2))
1256 !luaK_tonumeral(fs, e2, &v2) ||
1257 !validop(op, &v1, &v2))
1258 return 0; /* non-numeric operands or not safe to fold */ 1224 return 0; /* non-numeric operands or not safe to fold */
1259 luaO_rawarith(fs->ls->L, op, &v1, &v2, &res); /* does operation */ 1225 luaO_rawarith(fs->ls->L, op, &v1, &v2, &res); /* does operation */
1260 if (ttisinteger(&res)) { 1226 if (ttisinteger(&res)) {
@@ -1341,7 +1307,7 @@ static void codearith (FuncState *fs, OpCode op,
1341 expdesc *e1, expdesc *e2, int flip, int line) { 1307 expdesc *e1, expdesc *e2, int flip, int line) {
1342 if (isSCint(e2)) /* immediate operand? */ 1308 if (isSCint(e2)) /* immediate operand? */
1343 codebini(fs, cast(OpCode, op - OP_ADD + OP_ADDI), e1, e2, flip, line); 1309 codebini(fs, cast(OpCode, op - OP_ADD + OP_ADDI), e1, e2, flip, line);
1344 else if (luaK_tonumeral(fs, e2, NULL) && luaK_exp2K(fs, e2)) { /* K operand? */ 1310 else if (tonumeral(e2, NULL) && luaK_exp2K(fs, e2)) { /* K operand? */
1345 int v2 = e2->u.info; /* K index */ 1311 int v2 = e2->u.info; /* K index */
1346 op = cast(OpCode, op - OP_ADD + OP_ADDK); 1312 op = cast(OpCode, op - OP_ADD + OP_ADDK);
1347 finishbinexpval(fs, e1, e2, op, v2, flip, line); 1313 finishbinexpval(fs, e1, e2, op, v2, flip, line);
@@ -1362,7 +1328,7 @@ static void codearith (FuncState *fs, OpCode op,
1362static void codecommutative (FuncState *fs, OpCode op, 1328static void codecommutative (FuncState *fs, OpCode op,
1363 expdesc *e1, expdesc *e2, int line) { 1329 expdesc *e1, expdesc *e2, int line) {
1364 int flip = 0; 1330 int flip = 0;
1365 if (luaK_tonumeral(fs, e1, NULL)) { /* is first operand a numeric constant? */ 1331 if (tonumeral(e1, NULL)) { /* is first operand a numeric constant? */
1366 swapexps(e1, e2); /* change order */ 1332 swapexps(e1, e2); /* change order */
1367 flip = 1; 1333 flip = 1;
1368 } 1334 }
@@ -1519,13 +1485,13 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
1519 case OPR_MOD: case OPR_POW: 1485 case OPR_MOD: case OPR_POW:
1520 case OPR_BAND: case OPR_BOR: case OPR_BXOR: 1486 case OPR_BAND: case OPR_BOR: case OPR_BXOR:
1521 case OPR_SHL: case OPR_SHR: { 1487 case OPR_SHL: case OPR_SHR: {
1522 if (!luaK_tonumeral(fs, v, NULL)) 1488 if (!tonumeral(v, NULL))
1523 luaK_exp2anyreg(fs, v); 1489 luaK_exp2anyreg(fs, v);
1524 /* else keep numeral, which may be folded with 2nd operand */ 1490 /* else keep numeral, which may be folded with 2nd operand */
1525 break; 1491 break;
1526 } 1492 }
1527 case OPR_EQ: case OPR_NE: { 1493 case OPR_EQ: case OPR_NE: {
1528 if (!luaK_tonumeral(fs, v, NULL)) 1494 if (!tonumeral(v, NULL))
1529 luaK_exp2RK(fs, v); 1495 luaK_exp2RK(fs, v);
1530 /* else keep numeral, which may be an immediate operand */ 1496 /* else keep numeral, which may be an immediate operand */
1531 break; 1497 break;
diff --git a/lcode.h b/lcode.h
index c4953295..0758f88d 100644
--- a/lcode.h
+++ b/lcode.h
@@ -51,7 +51,6 @@ typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr;
51 51
52#define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t) 52#define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t)
53 53
54LUAI_FUNC int luaK_tonumeral (FuncState *fs, const expdesc *e, TValue *v);
55LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx); 54LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx);
56LUAI_FUNC int luaK_codeAsBx (FuncState *fs, OpCode o, int A, int Bx); 55LUAI_FUNC int luaK_codeAsBx (FuncState *fs, OpCode o, int A, int Bx);
57LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A, 56LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A,
diff --git a/ldump.c b/ldump.c
index c4475576..3d5b7b32 100644
--- a/ldump.c
+++ b/ldump.c
@@ -149,6 +149,7 @@ static void DumpUpvalues (const Proto *f, DumpState *D) {
149 for (i = 0; i < n; i++) { 149 for (i = 0; i < n; i++) {
150 DumpByte(f->upvalues[i].instack, D); 150 DumpByte(f->upvalues[i].instack, D);
151 DumpByte(f->upvalues[i].idx, D); 151 DumpByte(f->upvalues[i].idx, D);
152 DumpByte(f->upvalues[i].ro, D);
152 } 153 }
153} 154}
154 155
diff --git a/lobject.h b/lobject.h
index 403b6047..64366a94 100644
--- a/lobject.h
+++ b/lobject.h
@@ -460,6 +460,7 @@ typedef struct Upvaldesc {
460 TString *name; /* upvalue name (for debug information) */ 460 TString *name; /* upvalue name (for debug information) */
461 lu_byte instack; /* whether it is in stack (register) */ 461 lu_byte instack; /* whether it is in stack (register) */
462 lu_byte idx; /* index of upvalue (in stack or in outer function's list) */ 462 lu_byte idx; /* index of upvalue (in stack or in outer function's list) */
463 lu_byte ro; /* true if upvalue is read-only (const) */
463} Upvaldesc; 464} Upvaldesc;
464 465
465 466
diff --git a/lparser.c b/lparser.c
index 52486e08..1551cda9 100644
--- a/lparser.c
+++ b/lparser.c
@@ -156,13 +156,6 @@ static void init_exp (expdesc *e, expkind k, int i) {
156} 156}
157 157
158 158
159static void init_var (expdesc *e, expkind k, int i) {
160 e->f = e->t = NO_JUMP;
161 e->k = k;
162 e->u.var.idx = i;
163}
164
165
166static void codestring (LexState *ls, expdesc *e, TString *s) { 159static void codestring (LexState *ls, expdesc *e, TString *s) {
167 init_exp(e, VK, luaK_stringK(ls->fs, s)); 160 init_exp(e, VK, luaK_stringK(ls->fs, s));
168} 161}
@@ -177,16 +170,15 @@ static void codename (LexState *ls, expdesc *e) {
177** Register a new local variable in the active 'Proto' (for debug 170** Register a new local variable in the active 'Proto' (for debug
178** information). 171** information).
179*/ 172*/
180static int registerlocalvar (LexState *ls, TString *varname) { 173static int registerlocalvar (lua_State *L, FuncState *fs, TString *varname) {
181 FuncState *fs = ls->fs;
182 Proto *f = fs->f; 174 Proto *f = fs->f;
183 int oldsize = f->sizelocvars; 175 int oldsize = f->sizelocvars;
184 luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars, 176 luaM_growvector(L, f->locvars, fs->nlocvars, f->sizelocvars,
185 LocVar, SHRT_MAX, "local variables"); 177 LocVar, SHRT_MAX, "local variables");
186 while (oldsize < f->sizelocvars) 178 while (oldsize < f->sizelocvars)
187 f->locvars[oldsize++].varname = NULL; 179 f->locvars[oldsize++].varname = NULL;
188 f->locvars[fs->nlocvars].varname = varname; 180 f->locvars[fs->nlocvars].varname = varname;
189 luaC_objbarrier(ls->L, f, varname); 181 luaC_objbarrier(L, f, varname);
190 return fs->nlocvars++; 182 return fs->nlocvars++;
191} 183}
192 184
@@ -195,18 +187,19 @@ static int registerlocalvar (LexState *ls, TString *varname) {
195** Create a new local variable with the given 'name'. 187** Create a new local variable with the given 'name'.
196*/ 188*/
197static Vardesc *new_localvar (LexState *ls, TString *name) { 189static Vardesc *new_localvar (LexState *ls, TString *name) {
190 lua_State *L = ls->L;
198 FuncState *fs = ls->fs; 191 FuncState *fs = ls->fs;
199 Dyndata *dyd = ls->dyd; 192 Dyndata *dyd = ls->dyd;
200 Vardesc *var; 193 Vardesc *var;
201 int reg = registerlocalvar(ls, name); 194 int reg = registerlocalvar(L, fs, name);
202 checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal, 195 checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal,
203 MAXVARS, "local variables"); 196 MAXVARS, "local variables");
204 luaM_growvector(ls->L, dyd->actvar.arr, dyd->actvar.n + 1, 197 luaM_growvector(L, dyd->actvar.arr, dyd->actvar.n + 1,
205 dyd->actvar.size, Vardesc, MAX_INT, "local variables"); 198 dyd->actvar.size, Vardesc, USHRT_MAX, "local variables");
206 var = &dyd->actvar.arr[dyd->actvar.n++]; 199 var = &dyd->actvar.arr[dyd->actvar.n++];
207 var->idx = cast(short, reg); 200 var->pidx = cast(short, reg);
208 var->ro = 0; 201 var->ro = 0;
209 setnilvalue(&var->val); 202 setnilvalue(var);
210 return var; 203 return var;
211} 204}
212 205
@@ -223,50 +216,47 @@ static Vardesc *getlocalvardesc (FuncState *fs, int i) {
223 return &fs->ls->dyd->actvar.arr[fs->firstlocal + i]; 216 return &fs->ls->dyd->actvar.arr[fs->firstlocal + i];
224} 217}
225 218
219
226/* 220/*
227** Get the debug-information entry for current variable 'i'. 221** Get the debug-information entry for current variable 'i'.
228*/ 222*/
229static LocVar *getlocvar (FuncState *fs, int i) { 223static LocVar *localdebuginfo (FuncState *fs, int i) {
230 int idx = getlocalvardesc(fs, i)->idx; 224 int idx = getlocalvardesc(fs, i)->pidx;
231 lua_assert(idx < fs->nlocvars); 225 lua_assert(idx < fs->nlocvars);
232 return &fs->f->locvars[idx]; 226 return &fs->f->locvars[idx];
233} 227}
234 228
235 229
236/* 230static void init_var (FuncState *fs, expdesc *e, int i) {
237** Return the "variable description" (Vardesc) of a given 231 e->f = e->t = NO_JUMP;
238** local variable and update 'fs' to point to the function 232 e->k = VLOCAL;
239** where that variable was defined. Return NULL if expression 233 e->u.var.vidx = i;
240** is neither a local variable nor an upvalue. 234 e->u.var.sidx = getlocalvardesc(fs, i)->sidx;
241*/
242Vardesc *luaY_getvardesc (FuncState **fs, const expdesc *e) {
243 if (e->k == VLOCAL)
244 return getlocalvardesc(*fs, e->u.var.idx);
245 else if (e->k != VUPVAL)
246 return NULL; /* not a local variable */
247 else { /* upvalue: must go up all levels up to the original local */
248 int idx = e->u.var.idx;
249 for (;;) {
250 Upvaldesc *up = &(*fs)->f->upvalues[idx];
251 *fs = (*fs)->prev; /* must look at the previous level */
252 idx = up->idx; /* at this index */
253 if (*fs == NULL) /* no more levels? (can happen only with _ENV) */
254 return NULL;
255 else if (up->instack) /* got to the original level? */
256 return getlocalvardesc(*fs, idx);
257 /* else repeat for previous level */
258 }
259 }
260} 235}
261 236
262 237
263static void check_readonly (LexState *ls, expdesc *e) { 238static void check_readonly (LexState *ls, expdesc *e) {
264 FuncState *fs = ls->fs; 239 FuncState *fs = ls->fs;
265 Vardesc *vardesc = luaY_getvardesc(&fs, e); 240 TString *varname = NULL; /* to be set if variable is const */
266 if (vardesc && vardesc->ro) { /* is variable local and const? */ 241 switch (e->k) {
242 case VLOCAL: {
243 Vardesc *vardesc = getlocalvardesc(fs, e->u.var.vidx);
244 if (vardesc->ro)
245 varname = fs->f->locvars[vardesc->pidx].varname;
246 break;
247 }
248 case VUPVAL: {
249 Upvaldesc *up = &fs->f->upvalues[e->u.info];
250 if (up->ro)
251 varname = up->name;
252 break;
253 }
254 default:
255 return; /* other cases cannot be read-only */
256 }
257 if (varname) {
267 const char *msg = luaO_pushfstring(ls->L, 258 const char *msg = luaO_pushfstring(ls->L,
268 "attempt to assign to const variable '%s'", 259 "attempt to assign to const variable '%s'", getstr(varname));
269 getstr(fs->f->locvars[vardesc->idx].varname));
270 luaK_semerror(ls, msg); /* error */ 260 luaK_semerror(ls, msg); /* error */
271 } 261 }
272} 262}
@@ -274,13 +264,15 @@ static void check_readonly (LexState *ls, expdesc *e) {
274 264
275/* 265/*
276** Start the scope for the last 'nvars' created variables. 266** Start the scope for the last 'nvars' created variables.
277** (debug info.)
278*/ 267*/
279static void adjustlocalvars (LexState *ls, int nvars) { 268static void adjustlocalvars (LexState *ls, int nvars) {
280 FuncState *fs = ls->fs; 269 FuncState *fs = ls->fs;
281 fs->nactvar = cast_byte(fs->nactvar + nvars); 270 int i;
282 for (; nvars; nvars--) { 271 for (i = 0; i < nvars; i++) {
283 getlocvar(fs, fs->nactvar - nvars)->startpc = fs->pc; 272 int varidx = fs->nactvar++;
273 Vardesc *var = getlocalvardesc(fs, varidx);
274 var->sidx = varidx;
275 fs->f->locvars[var->pidx].startpc = fs->pc;
284 } 276 }
285} 277}
286 278
@@ -292,7 +284,7 @@ static void adjustlocalvars (LexState *ls, int nvars) {
292static void removevars (FuncState *fs, int tolevel) { 284static void removevars (FuncState *fs, int tolevel) {
293 fs->ls->dyd->actvar.n -= (fs->nactvar - tolevel); 285 fs->ls->dyd->actvar.n -= (fs->nactvar - tolevel);
294 while (fs->nactvar > tolevel) 286 while (fs->nactvar > tolevel)
295 getlocvar(fs, --fs->nactvar)->endpc = fs->pc; 287 localdebuginfo(fs, --fs->nactvar)->endpc = fs->pc;
296} 288}
297 289
298 290
@@ -310,7 +302,7 @@ static int searchupvalue (FuncState *fs, TString *name) {
310} 302}
311 303
312 304
313static int newupvalue (FuncState *fs, TString *name, expdesc *v) { 305static Upvaldesc *allocupvalue (FuncState *fs) {
314 Proto *f = fs->f; 306 Proto *f = fs->f;
315 int oldsize = f->sizeupvalues; 307 int oldsize = f->sizeupvalues;
316 checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues"); 308 checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues");
@@ -318,11 +310,28 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
318 Upvaldesc, MAXUPVAL, "upvalues"); 310 Upvaldesc, MAXUPVAL, "upvalues");
319 while (oldsize < f->sizeupvalues) 311 while (oldsize < f->sizeupvalues)
320 f->upvalues[oldsize++].name = NULL; 312 f->upvalues[oldsize++].name = NULL;
321 f->upvalues[fs->nups].instack = (v->k == VLOCAL); 313 return &f->upvalues[fs->nups++];
322 f->upvalues[fs->nups].idx = cast_byte(v->u.var.idx); 314}
323 f->upvalues[fs->nups].name = name; 315
324 luaC_objbarrier(fs->ls->L, f, name); 316
325 return fs->nups++; 317static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
318 Upvaldesc *up = allocupvalue(fs);
319 FuncState *prev = fs->prev;
320 if (v->k == VLOCAL) {
321 up->instack = 1;
322 up->idx = v->u.var.sidx;
323 up->ro = getlocalvardesc(prev, v->u.var.vidx)->ro;
324 lua_assert(eqstr(name, localdebuginfo(prev, v->u.var.vidx)->varname));
325 }
326 else {
327 up->instack = 0;
328 up->idx = cast_byte(v->u.info);
329 up->ro = prev->f->upvalues[v->u.info].ro;
330 lua_assert(eqstr(name, prev->f->upvalues[v->u.info].name));
331 }
332 up->name = name;
333 luaC_objbarrier(fs->ls->L, fs->f, name);
334 return fs->nups - 1;
326} 335}
327 336
328 337
@@ -333,7 +342,7 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
333static int searchvar (FuncState *fs, TString *n) { 342static int searchvar (FuncState *fs, TString *n) {
334 int i; 343 int i;
335 for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) { 344 for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) {
336 if (eqstr(n, getlocvar(fs, i)->varname)) 345 if (eqstr(n, localdebuginfo(fs, i)->varname))
337 return i; 346 return i;
338 } 347 }
339 return -1; /* not found */ 348 return -1; /* not found */
@@ -364,9 +373,9 @@ static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
364 else { 373 else {
365 int v = searchvar(fs, n); /* look up locals at current level */ 374 int v = searchvar(fs, n); /* look up locals at current level */
366 if (v >= 0) { /* found? */ 375 if (v >= 0) { /* found? */
367 init_var(var, VLOCAL, v); /* variable is local */ 376 init_var(fs, var, v); /* variable is local */
368 if (!base) 377 if (!base)
369 markupval(fs, v); /* local will be used as an upval */ 378 markupval(fs, var->u.var.sidx); /* local will be used as an upval */
370 } 379 }
371 else { /* not found as local at current level; try upvalues */ 380 else { /* not found as local at current level; try upvalues */
372 int idx = searchupvalue(fs, n); /* try existing upvalues */ 381 int idx = searchupvalue(fs, n); /* try existing upvalues */
@@ -377,7 +386,7 @@ static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
377 /* else was LOCAL or UPVAL */ 386 /* else was LOCAL or UPVAL */
378 idx = newupvalue(fs, n, var); /* will be a new upvalue */ 387 idx = newupvalue(fs, n, var); /* will be a new upvalue */
379 } 388 }
380 init_var(var, VUPVAL, idx); /* new or old upvalue */ 389 init_exp(var, VUPVAL, idx); /* new or old upvalue */
381 } 390 }
382 } 391 }
383} 392}
@@ -440,7 +449,7 @@ static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) {
440** local variable. 449** local variable.
441*/ 450*/
442static l_noret jumpscopeerror (LexState *ls, Labeldesc *gt) { 451static l_noret jumpscopeerror (LexState *ls, Labeldesc *gt) {
443 const char *varname = getstr(getlocvar(ls->fs, gt->nactvar)->varname); 452 const char *varname = getstr(localdebuginfo(ls->fs, gt->nactvar)->varname);
444 const char *msg = "<goto %s> at line %d jumps into the scope of local '%s'"; 453 const char *msg = "<goto %s> at line %d jumps into the scope of local '%s'";
445 msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line, varname); 454 msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line, varname);
446 luaK_semerror(ls, msg); /* raise the error */ 455 luaK_semerror(ls, msg); /* raise the error */
@@ -1259,20 +1268,20 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
1259 for (; lh; lh = lh->prev) { /* check all previous assignments */ 1268 for (; lh; lh = lh->prev) { /* check all previous assignments */
1260 if (vkisindexed(lh->v.k)) { /* assignment to table field? */ 1269 if (vkisindexed(lh->v.k)) { /* assignment to table field? */
1261 if (lh->v.k == VINDEXUP) { /* is table an upvalue? */ 1270 if (lh->v.k == VINDEXUP) { /* is table an upvalue? */
1262 if (v->k == VUPVAL && lh->v.u.ind.t == v->u.var.idx) { 1271 if (v->k == VUPVAL && lh->v.u.ind.t == v->u.info) {
1263 conflict = 1; /* table is the upvalue being assigned now */ 1272 conflict = 1; /* table is the upvalue being assigned now */
1264 lh->v.k = VINDEXSTR; 1273 lh->v.k = VINDEXSTR;
1265 lh->v.u.ind.t = extra; /* assignment will use safe copy */ 1274 lh->v.u.ind.t = extra; /* assignment will use safe copy */
1266 } 1275 }
1267 } 1276 }
1268 else { /* table is a register */ 1277 else { /* table is a register */
1269 if (v->k == VLOCAL && lh->v.u.ind.t == v->u.var.idx) { 1278 if (v->k == VLOCAL && lh->v.u.ind.t == v->u.var.sidx) {
1270 conflict = 1; /* table is the local being assigned now */ 1279 conflict = 1; /* table is the local being assigned now */
1271 lh->v.u.ind.t = extra; /* assignment will use safe copy */ 1280 lh->v.u.ind.t = extra; /* assignment will use safe copy */
1272 } 1281 }
1273 /* is index the local being assigned? */ 1282 /* is index the local being assigned? */
1274 if (lh->v.k == VINDEXED && v->k == VLOCAL && 1283 if (lh->v.k == VINDEXED && v->k == VLOCAL &&
1275 lh->v.u.ind.idx == v->u.var.idx) { 1284 lh->v.u.ind.idx == v->u.var.sidx) {
1276 conflict = 1; 1285 conflict = 1;
1277 lh->v.u.ind.idx = extra; /* previous assignment will use safe copy */ 1286 lh->v.u.ind.idx = extra; /* previous assignment will use safe copy */
1278 } 1287 }
@@ -1281,14 +1290,16 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
1281 } 1290 }
1282 if (conflict) { 1291 if (conflict) {
1283 /* copy upvalue/local value to a temporary (in position 'extra') */ 1292 /* copy upvalue/local value to a temporary (in position 'extra') */
1284 OpCode op = (v->k == VLOCAL) ? OP_MOVE : OP_GETUPVAL; 1293 if (v->k == VLOCAL)
1285 luaK_codeABC(fs, op, extra, v->u.var.idx, 0); 1294 luaK_codeABC(fs, OP_MOVE, extra, v->u.var.sidx, 0);
1295 else
1296 luaK_codeABC(fs, OP_GETUPVAL, extra, v->u.info, 0);
1286 luaK_reserveregs(fs, 1); 1297 luaK_reserveregs(fs, 1);
1287 } 1298 }
1288} 1299}
1289 1300
1290/* 1301/*
1291** Parse and compile a mulitple assignment. The first "variable" 1302** Parse and compile a multiple assignment. The first "variable"
1292** (a 'suffixedexp') was already read by the caller. 1303** (a 'suffixedexp') was already read by the caller.
1293** 1304**
1294** assignment -> suffixedexp restassign 1305** assignment -> suffixedexp restassign
@@ -1652,7 +1663,7 @@ static void localfunc (LexState *ls) {
1652 adjustlocalvars(ls, 1); /* enter its scope */ 1663 adjustlocalvars(ls, 1); /* enter its scope */
1653 body(ls, &b, 0, ls->linenumber); /* function created in next register */ 1664 body(ls, &b, 0, ls->linenumber); /* function created in next register */
1654 /* debug information will only see the variable after this point! */ 1665 /* debug information will only see the variable after this point! */
1655 getlocvar(fs, b.u.info)->startpc = fs->pc; 1666 localdebuginfo(fs, b.u.info)->startpc = fs->pc;
1656} 1667}
1657 1668
1658 1669
@@ -1870,11 +1881,14 @@ static void statement (LexState *ls) {
1870*/ 1881*/
1871static void mainfunc (LexState *ls, FuncState *fs) { 1882static void mainfunc (LexState *ls, FuncState *fs) {
1872 BlockCnt bl; 1883 BlockCnt bl;
1873 expdesc v; 1884 Upvaldesc *env;
1874 open_func(ls, fs, &bl); 1885 open_func(ls, fs, &bl);
1875 setvararg(fs, 0); /* main function is always declared vararg */ 1886 setvararg(fs, 0); /* main function is always declared vararg */
1876 init_var(&v, VLOCAL, 0); /* create and... */ 1887 env = allocupvalue(fs); /* ...set environment upvalue */
1877 newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */ 1888 env->instack = 1;
1889 env->idx = 0;
1890 env->ro = 0;
1891 env->name = ls->envn;
1878 luaX_next(ls); /* read first token */ 1892 luaX_next(ls); /* read first token */
1879 statlist(ls); /* parse main body */ 1893 statlist(ls); /* parse main body */
1880 check(ls, TK_EOS); 1894 check(ls, TK_EOS);
diff --git a/lparser.h b/lparser.h
index b708de25..cc2ec14d 100644
--- a/lparser.h
+++ b/lparser.h
@@ -33,8 +33,9 @@ typedef enum {
33 VKINT, /* integer constant; nval = numerical integer value */ 33 VKINT, /* integer constant; nval = numerical integer value */
34 VNONRELOC, /* expression has its value in a fixed register; 34 VNONRELOC, /* expression has its value in a fixed register;
35 info = result register */ 35 info = result register */
36 VLOCAL, /* local variable; var.idx = local register */ 36 VLOCAL, /* local variable; var.ridx = local register;
37 VUPVAL, /* upvalue variable; var.idx = index of upvalue in 'upvalues' */ 37 var.vidx = index in 'actvar.arr' */
38 VUPVAL, /* upvalue variable; info = index of upvalue in 'upvalues' */
38 VINDEXED, /* indexed variable; 39 VINDEXED, /* indexed variable;
39 ind.t = table register; 40 ind.t = table register;
40 ind.idx = key's R index */ 41 ind.idx = key's R index */
@@ -70,8 +71,9 @@ typedef struct expdesc {
70 short idx; /* index (R or "long" K) */ 71 short idx; /* index (R or "long" K) */
71 lu_byte t; /* table (register or upvalue) */ 72 lu_byte t; /* table (register or upvalue) */
72 } ind; 73 } ind;
73 struct { /* for local variables and upvalues */ 74 struct { /* for local variables */
74 lu_byte idx; /* index of the variable */ 75 lu_byte sidx; /* index in the stack */
76 unsigned short vidx; /* index in 'actvar.arr' */
75 } var; 77 } var;
76 } u; 78 } u;
77 int t; /* patch list of 'exit when true' */ 79 int t; /* patch list of 'exit when true' */
@@ -81,9 +83,10 @@ typedef struct expdesc {
81 83
82/* description of an active local variable */ 84/* description of an active local variable */
83typedef struct Vardesc { 85typedef struct Vardesc {
84 TValue val; /* constant value (if variable is 'const') */ 86 TValuefields; /* constant value (if variable is 'const') */
85 short idx; /* index of the variable in the Proto's 'locvars' array */
86 lu_byte ro; /* true if variable is 'const' */ 87 lu_byte ro; /* true if variable is 'const' */
88 lu_byte sidx; /* index of the variable in the stack */
89 short pidx; /* index of the variable in the Proto's 'locvars' array */
87} Vardesc; 90} Vardesc;
88 91
89 92
@@ -144,7 +147,6 @@ typedef struct FuncState {
144} FuncState; 147} FuncState;
145 148
146 149
147LUAI_FUNC Vardesc *luaY_getvardesc (FuncState **fs, const expdesc *e);
148LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, 150LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
149 Dyndata *dyd, const char *name, int firstchar); 151 Dyndata *dyd, const char *name, int firstchar);
150 152
diff --git a/lundump.c b/lundump.c
index c1cff9e1..5c0e94d6 100644
--- a/lundump.c
+++ b/lundump.c
@@ -203,6 +203,7 @@ static void LoadUpvalues (LoadState *S, Proto *f) {
203 for (i = 0; i < n; i++) { 203 for (i = 0; i < n; i++) {
204 f->upvalues[i].instack = LoadByte(S); 204 f->upvalues[i].instack = LoadByte(S);
205 f->upvalues[i].idx = LoadByte(S); 205 f->upvalues[i].idx = LoadByte(S);
206 f->upvalues[i].ro = LoadByte(S);
206 } 207 }
207} 208}
208 209
diff --git a/testes/locals.lua b/testes/locals.lua
index 50230a27..0de00a98 100644
--- a/testes/locals.lua
+++ b/testes/locals.lua
@@ -177,14 +177,24 @@ do -- constants
177 local <const> a, b, <const> c = 10, 20, 30 177 local <const> a, b, <const> c = 10, 20, 30
178 b = a + c + b -- 'b' is not constant 178 b = a + c + b -- 'b' is not constant
179 assert(a == 10 and b == 60 and c == 30) 179 assert(a == 10 and b == 60 and c == 30)
180 local function checkro (code, name) 180 local function checkro (name, code)
181 local st, msg = load(code) 181 local st, msg = load(code)
182 local gab = string.format("attempt to assign to const variable '%s'", name) 182 local gab = string.format("attempt to assign to const variable '%s'", name)
183 assert(not st and string.find(msg, gab)) 183 assert(not st and string.find(msg, gab))
184 end 184 end
185 checkro("local x, <const> y, z = 10, 20, 30; x = 11; y = 12", "y") 185 checkro("y", "local x, <const> y, z = 10, 20, 30; x = 11; y = 12")
186 checkro("local <const> x, y, <const> z = 10, 20, 30; x = 11", "x") 186 checkro("x", "local <const> x, y, <const> z = 10, 20, 30; x = 11")
187 checkro("local <const> x, y, <const> z = 10, 20, 30; y = 10; z = 11", "z") 187 checkro("z", "local <const> x, y, <const> z = 10, 20, 30; y = 10; z = 11")
188
189 checkro("z", [[
190 local a, <const> z, b = 10;
191 function foo() a = 20; z = 32; end
192 ]])
193
194 checkro("var1", [[
195 local a, <const> var1 = 10;
196 function foo() a = 20; z = function () var1 = 12; end end
197 ]])
188end 198end
189 199
190 200