diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-07-09 10:43:17 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-07-09 10:43:17 -0300 |
commit | 54f7b46c1e8a0188e1649046a3a72522f2d769f4 (patch) | |
tree | 28e973e10e2bc82de4d7d1e7a9f6673b028f7ad2 /lparser.c | |
parent | e888976bc6ba5592fb8ab8ecc04a8f63e217aa74 (diff) | |
download | lua-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.
Diffstat (limited to 'lparser.c')
-rw-r--r-- | lparser.c | 158 |
1 files changed, 86 insertions, 72 deletions
@@ -156,13 +156,6 @@ static void init_exp (expdesc *e, expkind k, int i) { | |||
156 | } | 156 | } |
157 | 157 | ||
158 | 158 | ||
159 | static 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 | |||
166 | static void codestring (LexState *ls, expdesc *e, TString *s) { | 159 | static 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 | */ |
180 | static int registerlocalvar (LexState *ls, TString *varname) { | 173 | static 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 | */ |
197 | static Vardesc *new_localvar (LexState *ls, TString *name) { | 189 | static 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 | */ |
229 | static LocVar *getlocvar (FuncState *fs, int i) { | 223 | static 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 | /* | 230 | static 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 | */ | ||
242 | Vardesc *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 | ||
263 | static void check_readonly (LexState *ls, expdesc *e) { | 238 | static 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 | */ |
279 | static void adjustlocalvars (LexState *ls, int nvars) { | 268 | static 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) { | |||
292 | static void removevars (FuncState *fs, int tolevel) { | 284 | static 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 | ||
313 | static int newupvalue (FuncState *fs, TString *name, expdesc *v) { | 305 | static 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++; | 317 | static 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) { | |||
333 | static int searchvar (FuncState *fs, TString *n) { | 342 | static 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 | */ |
442 | static l_noret jumpscopeerror (LexState *ls, Labeldesc *gt) { | 451 | static 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 | */ |
1871 | static void mainfunc (LexState *ls, FuncState *fs) { | 1882 | static 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); |