aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2019-07-12 11:38:42 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2019-07-12 11:38:42 -0300
commitf6aab3ec1f111cd8d968bdcb7ca800e93b819d24 (patch)
tree4c36c418ecc9062e6d95de73457198b38b0afce9
parentbe8445d7e4b6122620c428877b51a27d464253d5 (diff)
downloadlua-f6aab3ec1f111cd8d968bdcb7ca800e93b819d24.tar.gz
lua-f6aab3ec1f111cd8d968bdcb7ca800e93b819d24.tar.bz2
lua-f6aab3ec1f111cd8d968bdcb7ca800e93b819d24.zip
First implementation of constant propagation
Local constant variables initialized with compile-time constants are optimized away from the code.
-rw-r--r--lcode.c56
-rw-r--r--lcode.h1
-rw-r--r--ldump.c2
-rw-r--r--lobject.h2
-rw-r--r--lparser.c113
-rw-r--r--lparser.h27
-rw-r--r--lundump.c5
-rw-r--r--manual/manual.of31
-rw-r--r--testes/code.lua89
-rw-r--r--testes/constructs.lua24
-rw-r--r--testes/locals.lua2
-rw-r--r--testes/math.lua16
12 files changed, 249 insertions, 119 deletions
diff --git a/lcode.c b/lcode.c
index 837253f4..74ff47de 100644
--- a/lcode.c
+++ b/lcode.c
@@ -68,6 +68,30 @@ static int tonumeral (const expdesc *e, TValue *v) {
68 68
69 69
70/* 70/*
71** If expression is a constant, fills 'v' with its value
72** and returns 1. Otherwise, returns 0.
73*/
74int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v) {
75 if (hasjumps(e))
76 return 0; /* not a constant */
77 switch (e->k) {
78 case VFALSE: case VTRUE:
79 setbvalue(v, e->k == VTRUE);
80 return 1;
81 case VNIL:
82 setnilvalue(v);
83 return 1;
84 case VK: {
85 TValue *k = &fs->f->k[e->u.info];
86 setobj(fs->ls->L, v, k);
87 return 1;
88 }
89 default: return tonumeral(e, v);
90 }
91}
92
93
94/*
71** Return the previous instruction of the current code. If there 95** Return the previous instruction of the current code. If there
72** may be a jump target between the current instruction and the 96** may be a jump target between the current instruction and the
73** previous one, return an invalid instruction (to avoid wrong 97** previous one, return an invalid instruction (to avoid wrong
@@ -630,6 +654,31 @@ static void luaK_float (FuncState *fs, int reg, lua_Number f) {
630 654
631 655
632/* 656/*
657** Convert a constant in 'v' into an expression description 'e'
658*/
659static void const2exp (FuncState *fs, TValue *v, expdesc *e) {
660 switch (ttypetag(v)) {
661 case LUA_TNUMINT:
662 e->k = VKINT; e->u.ival = ivalue(v);
663 break;
664 case LUA_TNUMFLT:
665 e->k = VKFLT; e->u.nval = fltvalue(v);
666 break;
667 case LUA_TBOOLEAN:
668 e->k = bvalue(v) ? VTRUE : VFALSE;
669 break;
670 case LUA_TNIL:
671 e->k = VNIL;
672 break;
673 case LUA_TSHRSTR: case LUA_TLNGSTR:
674 e->k = VK; e->u.info = luaK_stringK(fs, tsvalue(v));
675 break;
676 default: lua_assert(0);
677 }
678}
679
680
681/*
633** Fix an expression to return the number of results 'nresults'. 682** Fix an expression to return the number of results 'nresults'.
634** Either 'e' is a multi-ret expression (function call or vararg) 683** Either 'e' is a multi-ret expression (function call or vararg)
635** or 'nresults' is LUA_MULTRET (as any expression can satisfy that). 684** or 'nresults' is LUA_MULTRET (as any expression can satisfy that).
@@ -677,6 +726,11 @@ void luaK_setoneret (FuncState *fs, expdesc *e) {
677*/ 726*/
678void luaK_dischargevars (FuncState *fs, expdesc *e) { 727void luaK_dischargevars (FuncState *fs, expdesc *e) {
679 switch (e->k) { 728 switch (e->k) {
729 case VCONST: {
730 TValue *val = &fs->ls->dyd->actvar.arr[e->u.info].k;
731 const2exp(fs, val, e);
732 break;
733 }
680 case VLOCAL: { /* already in a register */ 734 case VLOCAL: { /* already in a register */
681 e->u.info = e->u.var.sidx; 735 e->u.info = e->u.var.sidx;
682 e->k = VNONRELOC; /* becomes a non-relocatable value */ 736 e->k = VNONRELOC; /* becomes a non-relocatable value */
@@ -1074,7 +1128,6 @@ void luaK_goiffalse (FuncState *fs, expdesc *e) {
1074** Code 'not e', doing constant folding. 1128** Code 'not e', doing constant folding.
1075*/ 1129*/
1076static void codenot (FuncState *fs, expdesc *e) { 1130static void codenot (FuncState *fs, expdesc *e) {
1077 luaK_dischargevars(fs, e);
1078 switch (e->k) { 1131 switch (e->k) {
1079 case VNIL: case VFALSE: { 1132 case VNIL: case VFALSE: {
1080 e->k = VTRUE; /* true == not nil == not false */ 1133 e->k = VTRUE; /* true == not nil == not false */
@@ -1447,6 +1500,7 @@ static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
1447*/ 1500*/
1448void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) { 1501void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) {
1449 static const expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP}; 1502 static const expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP};
1503 luaK_dischargevars(fs, e);
1450 switch (op) { 1504 switch (op) {
1451 case OPR_MINUS: case OPR_BNOT: /* use 'ef' as fake 2nd operand */ 1505 case OPR_MINUS: case OPR_BNOT: /* use 'ef' as fake 2nd operand */
1452 if (constfolding(fs, op + LUA_OPUNM, e, &ef)) 1506 if (constfolding(fs, op + LUA_OPUNM, e, &ef))
diff --git a/lcode.h b/lcode.h
index 0758f88d..a15b6875 100644
--- a/lcode.h
+++ b/lcode.h
@@ -56,6 +56,7 @@ LUAI_FUNC int luaK_codeAsBx (FuncState *fs, OpCode o, int A, int Bx);
56LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A, 56LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A,
57 int B, int C, int k); 57 int B, int C, int k);
58LUAI_FUNC int luaK_isKint (expdesc *e); 58LUAI_FUNC int luaK_isKint (expdesc *e);
59LUAI_FUNC int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v);
59LUAI_FUNC void luaK_fixline (FuncState *fs, int line); 60LUAI_FUNC void luaK_fixline (FuncState *fs, int line);
60LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n); 61LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n);
61LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n); 62LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n);
diff --git a/ldump.c b/ldump.c
index 3d5b7b32..9b501729 100644
--- a/ldump.c
+++ b/ldump.c
@@ -149,7 +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 DumpByte(f->upvalues[i].kind, D);
153 } 153 }
154} 154}
155 155
diff --git a/lobject.h b/lobject.h
index 64366a94..2f95bcb5 100644
--- a/lobject.h
+++ b/lobject.h
@@ -460,7 +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 lu_byte kind; /* kind of corresponding variable */
464} Upvaldesc; 464} Upvaldesc;
465 465
466 466
diff --git a/lparser.c b/lparser.c
index 7f282bf9..79df0217 100644
--- a/lparser.c
+++ b/lparser.c
@@ -170,15 +170,16 @@ static void codename (LexState *ls, expdesc *e) {
170** Register a new local variable in the active 'Proto' (for debug 170** Register a new local variable in the active 'Proto' (for debug
171** information). 171** information).
172*/ 172*/
173static int registerlocalvar (lua_State *L, FuncState *fs, TString *varname) { 173static int registerlocalvar (LexState *ls, FuncState *fs, TString *varname) {
174 Proto *f = fs->f; 174 Proto *f = fs->f;
175 int oldsize = f->sizelocvars; 175 int oldsize = f->sizelocvars;
176 luaM_growvector(L, f->locvars, fs->ndebugvars, f->sizelocvars, 176 luaM_growvector(ls->L, f->locvars, fs->ndebugvars, f->sizelocvars,
177 LocVar, SHRT_MAX, "local variables"); 177 LocVar, SHRT_MAX, "local variables");
178 while (oldsize < f->sizelocvars) 178 while (oldsize < f->sizelocvars)
179 f->locvars[oldsize++].varname = NULL; 179 f->locvars[oldsize++].varname = NULL;
180 f->locvars[fs->ndebugvars].varname = varname; 180 f->locvars[fs->ndebugvars].varname = varname;
181 luaC_objbarrier(L, f, varname); 181 f->locvars[fs->ndebugvars].startpc = fs->pc;
182 luaC_objbarrier(ls->L, f, varname);
182 return fs->ndebugvars++; 183 return fs->ndebugvars++;
183} 184}
184 185
@@ -191,16 +192,13 @@ static Vardesc *new_localvar (LexState *ls, TString *name) {
191 FuncState *fs = ls->fs; 192 FuncState *fs = ls->fs;
192 Dyndata *dyd = ls->dyd; 193 Dyndata *dyd = ls->dyd;
193 Vardesc *var; 194 Vardesc *var;
194 int reg = registerlocalvar(L, fs, name);
195 checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal, 195 checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal,
196 MAXVARS, "local variables"); 196 MAXVARS, "local variables");
197 luaM_growvector(L, dyd->actvar.arr, dyd->actvar.n + 1, 197 luaM_growvector(L, dyd->actvar.arr, dyd->actvar.n + 1,
198 dyd->actvar.size, Vardesc, USHRT_MAX, "local variables"); 198 dyd->actvar.size, Vardesc, USHRT_MAX, "local variables");
199 var = &dyd->actvar.arr[dyd->actvar.n++]; 199 var = &dyd->actvar.arr[dyd->actvar.n++];
200 var->pidx = cast(short, reg); 200 var->vd.kind = VDKREG; /* default is a regular variable */
201 var->ro = 0; 201 var->vd.name = name;
202 var->name = name;
203 setnilvalue(var);
204 return var; 202 return var;
205} 203}
206 204
@@ -225,8 +223,8 @@ static Vardesc *getlocalvardesc (FuncState *fs, int i) {
225static int stacklevel (FuncState *fs, int nvar) { 223static int stacklevel (FuncState *fs, int nvar) {
226 while (nvar > 0) { 224 while (nvar > 0) {
227 Vardesc *vd = getlocalvardesc(fs, nvar - 1); 225 Vardesc *vd = getlocalvardesc(fs, nvar - 1);
228 if (vdinstack(vd)) /* is in the stack? */ 226 if (vd->vd.kind != RDKCTC) /* is in the stack? */
229 return vd->sidx + 1; 227 return vd->vd.sidx + 1;
230 else 228 else
231 nvar--; /* try previous variable */ 229 nvar--; /* try previous variable */
232 } 230 }
@@ -247,10 +245,10 @@ int luaY_nvarstack (FuncState *fs) {
247*/ 245*/
248static LocVar *localdebuginfo (FuncState *fs, int i) { 246static LocVar *localdebuginfo (FuncState *fs, int i) {
249 Vardesc *vd = getlocalvardesc(fs, i); 247 Vardesc *vd = getlocalvardesc(fs, i);
250 if (!vdinstack(vd)) 248 if (vd->vd.kind == RDKCTC)
251 return NULL; /* no debug info. for constants */ 249 return NULL; /* no debug info. for constants */
252 else { 250 else {
253 int idx = vd->pidx; 251 int idx = vd->vd.pidx;
254 lua_assert(idx < fs->ndebugvars); 252 lua_assert(idx < fs->ndebugvars);
255 return &fs->f->locvars[idx]; 253 return &fs->f->locvars[idx];
256 } 254 }
@@ -261,7 +259,7 @@ static void init_var (FuncState *fs, expdesc *e, int i) {
261 e->f = e->t = NO_JUMP; 259 e->f = e->t = NO_JUMP;
262 e->k = VLOCAL; 260 e->k = VLOCAL;
263 e->u.var.vidx = i; 261 e->u.var.vidx = i;
264 e->u.var.sidx = getlocalvardesc(fs, i)->sidx; 262 e->u.var.sidx = getlocalvardesc(fs, i)->vd.sidx;
265} 263}
266 264
267 265
@@ -269,15 +267,19 @@ static void check_readonly (LexState *ls, expdesc *e) {
269 FuncState *fs = ls->fs; 267 FuncState *fs = ls->fs;
270 TString *varname = NULL; /* to be set if variable is const */ 268 TString *varname = NULL; /* to be set if variable is const */
271 switch (e->k) { 269 switch (e->k) {
270 case VCONST: {
271 varname = ls->dyd->actvar.arr[e->u.info].vd.name;
272 break;
273 }
272 case VLOCAL: { 274 case VLOCAL: {
273 Vardesc *vardesc = getlocalvardesc(fs, e->u.var.vidx); 275 Vardesc *vardesc = getlocalvardesc(fs, e->u.var.vidx);
274 if (vardesc->ro) 276 if (vardesc->vd.kind != VDKREG) /* not a regular variable? */
275 varname = vardesc->name; 277 varname = vardesc->vd.name;
276 break; 278 break;
277 } 279 }
278 case VUPVAL: { 280 case VUPVAL: {
279 Upvaldesc *up = &fs->f->upvalues[e->u.info]; 281 Upvaldesc *up = &fs->f->upvalues[e->u.info];
280 if (up->ro) 282 if (up->kind != VDKREG)
281 varname = up->name; 283 varname = up->name;
282 break; 284 break;
283 } 285 }
@@ -302,8 +304,8 @@ static void adjustlocalvars (LexState *ls, int nvars) {
302 for (i = 0; i < nvars; i++) { 304 for (i = 0; i < nvars; i++) {
303 int varidx = fs->nactvar++; 305 int varidx = fs->nactvar++;
304 Vardesc *var = getlocalvardesc(fs, varidx); 306 Vardesc *var = getlocalvardesc(fs, varidx);
305 var->sidx = stklevel++; 307 var->vd.sidx = stklevel++;
306 fs->f->locvars[var->pidx].startpc = fs->pc; 308 var->vd.pidx = registerlocalvar(ls, fs, var->vd.name);
307 } 309 }
308} 310}
309 311
@@ -354,13 +356,13 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
354 if (v->k == VLOCAL) { 356 if (v->k == VLOCAL) {
355 up->instack = 1; 357 up->instack = 1;
356 up->idx = v->u.var.sidx; 358 up->idx = v->u.var.sidx;
357 up->ro = getlocalvardesc(prev, v->u.var.vidx)->ro; 359 up->kind = getlocalvardesc(prev, v->u.var.vidx)->vd.kind;
358 lua_assert(eqstr(name, getlocalvardesc(prev, v->u.var.vidx)->name)); 360 lua_assert(eqstr(name, getlocalvardesc(prev, v->u.var.vidx)->vd.name));
359 } 361 }
360 else { 362 else {
361 up->instack = 0; 363 up->instack = 0;
362 up->idx = cast_byte(v->u.info); 364 up->idx = cast_byte(v->u.info);
363 up->ro = prev->f->upvalues[v->u.info].ro; 365 up->kind = prev->f->upvalues[v->u.info].kind;
364 lua_assert(eqstr(name, prev->f->upvalues[v->u.info].name)); 366 lua_assert(eqstr(name, prev->f->upvalues[v->u.info].name));
365 } 367 }
366 up->name = name; 368 up->name = name;
@@ -373,11 +375,17 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
373** Look for an active local variable with the name 'n' in the 375** Look for an active local variable with the name 'n' in the
374** function 'fs'. 376** function 'fs'.
375*/ 377*/
376static int searchvar (FuncState *fs, TString *n) { 378static int searchvar (FuncState *fs, TString *n, expdesc *var) {
377 int i; 379 int i;
378 for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) { 380 for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) {
379 if (eqstr(n, getlocalvardesc(fs, i)->name)) 381 Vardesc *vd = getlocalvardesc(fs, i);
380 return i; 382 if (eqstr(n, vd->vd.name)) { /* found? */
383 if (vd->vd.kind == RDKCTC) /* compile-time constant? */
384 init_exp(var, VCONST, fs->firstlocal + i);
385 else /* real variable */
386 init_var(fs, var, i);
387 return var->k;
388 }
381 } 389 }
382 return -1; /* not found */ 390 return -1; /* not found */
383} 391}
@@ -405,20 +413,19 @@ static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
405 if (fs == NULL) /* no more levels? */ 413 if (fs == NULL) /* no more levels? */
406 init_exp(var, VVOID, 0); /* default is global */ 414 init_exp(var, VVOID, 0); /* default is global */
407 else { 415 else {
408 int v = searchvar(fs, n); /* look up locals at current level */ 416 int v = searchvar(fs, n, var); /* look up locals at current level */
409 if (v >= 0) { /* found? */ 417 if (v >= 0) { /* found? */
410 init_var(fs, var, v); /* variable is local */ 418 if (v == VLOCAL && !base)
411 if (!base)
412 markupval(fs, var->u.var.vidx); /* local will be used as an upval */ 419 markupval(fs, var->u.var.vidx); /* local will be used as an upval */
413 } 420 }
414 else { /* not found as local at current level; try upvalues */ 421 else { /* not found as local at current level; try upvalues */
415 int idx = searchupvalue(fs, n); /* try existing upvalues */ 422 int idx = searchupvalue(fs, n); /* try existing upvalues */
416 if (idx < 0) { /* not found? */ 423 if (idx < 0) { /* not found? */
417 singlevaraux(fs->prev, n, var, 0); /* try upper levels */ 424 singlevaraux(fs->prev, n, var, 0); /* try upper levels */
418 if (var->k == VVOID) /* not found? */ 425 if (var->k == VLOCAL || var->k == VUPVAL) /* local or upvalue? */
419 return; /* it is a global */ 426 idx = newupvalue(fs, n, var); /* will be a new upvalue */
420 /* else was LOCAL or UPVAL */ 427 else /* it is a global or a constant */
421 idx = newupvalue(fs, n, var); /* will be a new upvalue */ 428 return; /* don't need to do anything at this level */
422 } 429 }
423 init_exp(var, VUPVAL, idx); /* new or old upvalue */ 430 init_exp(var, VUPVAL, idx); /* new or old upvalue */
424 } 431 }
@@ -483,7 +490,7 @@ static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) {
483** local variable. 490** local variable.
484*/ 491*/
485static l_noret jumpscopeerror (LexState *ls, Labeldesc *gt) { 492static l_noret jumpscopeerror (LexState *ls, Labeldesc *gt) {
486 const char *varname = getstr(getlocalvardesc(ls->fs, gt->nactvar)->name); 493 const char *varname = getstr(getlocalvardesc(ls->fs, gt->nactvar)->vd.name);
487 const char *msg = "<goto %s> at line %d jumps into the scope of local '%s'"; 494 const char *msg = "<goto %s> at line %d jumps into the scope of local '%s'";
488 msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line, varname); 495 msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line, varname);
489 luaK_semerror(ls, msg); /* raise the error */ 496 luaK_semerror(ls, msg); /* raise the error */
@@ -1710,21 +1717,20 @@ static int getlocalattribute (LexState *ls) {
1710 const char *attr = getstr(str_checkname(ls)); 1717 const char *attr = getstr(str_checkname(ls));
1711 checknext(ls, '>'); 1718 checknext(ls, '>');
1712 if (strcmp(attr, "const") == 0) 1719 if (strcmp(attr, "const") == 0)
1713 return 1; /* read-only variable */ 1720 return RDKCONST; /* read-only variable */
1714 else if (strcmp(attr, "toclose") == 0) 1721 else if (strcmp(attr, "toclose") == 0)
1715 return 2; /* to-be-closed variable */ 1722 return RDKTOCLOSE; /* to-be-closed variable */
1716 else 1723 else
1717 luaK_semerror(ls, 1724 luaK_semerror(ls,
1718 luaO_pushfstring(ls->L, "unknown attribute '%s'", attr)); 1725 luaO_pushfstring(ls->L, "unknown attribute '%s'", attr));
1719 } 1726 }
1720 return 0; 1727 return VDKREG;
1721} 1728}
1722 1729
1723 1730
1724static void checktoclose (LexState *ls, int toclose) { 1731static void checktoclose (LexState *ls, int level) {
1725 if (toclose != -1) { /* is there a to-be-closed variable? */ 1732 if (level != -1) { /* is there a to-be-closed variable? */
1726 FuncState *fs = ls->fs; 1733 FuncState *fs = ls->fs;
1727 int level = luaY_nvarstack(fs) + toclose;
1728 markupval(fs, level + 1); 1734 markupval(fs, level + 1);
1729 fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */ 1735 fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */
1730 luaK_codeABC(fs, OP_TBC, level, 0, 0); 1736 luaK_codeABC(fs, OP_TBC, level, 0, 0);
@@ -1734,20 +1740,20 @@ static void checktoclose (LexState *ls, int toclose) {
1734 1740
1735static void localstat (LexState *ls) { 1741static void localstat (LexState *ls) {
1736 /* stat -> LOCAL ATTRIB NAME {',' ATTRIB NAME} ['=' explist] */ 1742 /* stat -> LOCAL ATTRIB NAME {',' ATTRIB NAME} ['=' explist] */
1743 FuncState *fs = ls->fs;
1737 int toclose = -1; /* index of to-be-closed variable (if any) */ 1744 int toclose = -1; /* index of to-be-closed variable (if any) */
1745 Vardesc *var; /* last variable */
1738 int nvars = 0; 1746 int nvars = 0;
1739 int nexps; 1747 int nexps;
1740 expdesc e; 1748 expdesc e;
1741 do { 1749 do {
1742 int kind = getlocalattribute(ls); 1750 int kind = getlocalattribute(ls);
1743 Vardesc *var = new_localvar(ls, str_checkname(ls)); 1751 var = new_localvar(ls, str_checkname(ls));
1744 if (kind != 0) { /* is there an attribute? */ 1752 var->vd.kind = kind;
1745 var->ro = 1; /* all attributes make variable read-only */ 1753 if (kind == RDKTOCLOSE) { /* to-be-closed? */
1746 if (kind == 2) { /* to-be-closed? */ 1754 if (toclose != -1) /* one already present? */
1747 if (toclose != -1) /* one already present? */ 1755 luaK_semerror(ls, "multiple to-be-closed variables in local list");
1748 luaK_semerror(ls, "multiple to-be-closed variables in local list"); 1756 toclose = luaY_nvarstack(fs) + nvars;
1749 toclose = nvars;
1750 }
1751 } 1757 }
1752 nvars++; 1758 nvars++;
1753 } while (testnext(ls, ',')); 1759 } while (testnext(ls, ','));
@@ -1757,9 +1763,18 @@ static void localstat (LexState *ls) {
1757 e.k = VVOID; 1763 e.k = VVOID;
1758 nexps = 0; 1764 nexps = 0;
1759 } 1765 }
1760 adjust_assign(ls, nvars, nexps, &e); 1766 if (nvars == nexps && /* no adjustments? */
1767 var->vd.kind == RDKCONST && /* last variable is const? */
1768 luaK_exp2const(fs, &e, &var->k)) { /* compile-time constant? */
1769 var->vd.kind = RDKCTC; /* variable is a compile-time constant */
1770 adjustlocalvars(ls, nvars - 1); /* exclude last variable */
1771 fs->nactvar++; /* but count it */
1772 }
1773 else {
1774 adjust_assign(ls, nvars, nexps, &e);
1775 adjustlocalvars(ls, nvars);
1776 }
1761 checktoclose(ls, toclose); 1777 checktoclose(ls, toclose);
1762 adjustlocalvars(ls, nvars);
1763} 1778}
1764 1779
1765 1780
@@ -1925,7 +1940,7 @@ static void mainfunc (LexState *ls, FuncState *fs) {
1925 env = allocupvalue(fs); /* ...set environment upvalue */ 1940 env = allocupvalue(fs); /* ...set environment upvalue */
1926 env->instack = 1; 1941 env->instack = 1;
1927 env->idx = 0; 1942 env->idx = 0;
1928 env->ro = 0; 1943 env->kind = VDKREG;
1929 env->name = ls->envn; 1944 env->name = ls->envn;
1930 luaX_next(ls); /* read first token */ 1945 luaX_next(ls); /* read first token */
1931 statlist(ls); /* parse main body */ 1946 statlist(ls); /* parse main body */
diff --git a/lparser.h b/lparser.h
index 7d43a813..d9b734bf 100644
--- a/lparser.h
+++ b/lparser.h
@@ -34,8 +34,9 @@ typedef enum {
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.ridx = local register; 36 VLOCAL, /* local variable; var.ridx = local register;
37 var.vidx = index in 'actvar.arr' */ 37 var.vidx = relative index in 'actvar.arr' */
38 VUPVAL, /* upvalue variable; info = index of upvalue in 'upvalues' */ 38 VUPVAL, /* upvalue variable; info = index of upvalue in 'upvalues' */
39 VCONST, /* compile-time constant; info = absolute index in 'actvar.arr' */
39 VINDEXED, /* indexed variable; 40 VINDEXED, /* indexed variable;
40 ind.t = table register; 41 ind.t = table register;
41 ind.idx = key's R index */ 42 ind.idx = key's R index */
@@ -81,19 +82,25 @@ typedef struct expdesc {
81} expdesc; 82} expdesc;
82 83
83 84
85/* kinds of variables */
86#define VDKREG 0 /* regular */
87#define RDKCONST 1 /* constant */
88#define RDKTOCLOSE 2 /* to-be-closed */
89#define RDKCTC 3 /* compile-time constant */
90
84/* description of an active local variable */ 91/* description of an active local variable */
85typedef struct Vardesc { 92typedef union Vardesc {
86 TValuefields; /* constant value (if it is a compile-time constant) */ 93 struct {
87 lu_byte ro; /* true if variable is 'const' */ 94 TValuefields; /* constant value (if it is a compile-time constant) */
88 lu_byte sidx; /* index of the variable in the stack */ 95 lu_byte kind;
89 short pidx; /* index of the variable in the Proto's 'locvars' array */ 96 lu_byte sidx; /* index of the variable in the stack */
90 TString *name; /* variable name */ 97 short pidx; /* index of the variable in the Proto's 'locvars' array */
98 TString *name; /* variable name */
99 } vd;
100 TValue k; /* constant value (if any) */
91} Vardesc; 101} Vardesc;
92 102
93 103
94/* check whether Vardesc is in the stack (not a compile-time constant) */
95#define vdinstack(vd) (ttisnil(vd))
96
97 104
98/* description of pending goto statements and label statements */ 105/* description of pending goto statements and label statements */
99typedef struct Labeldesc { 106typedef struct Labeldesc {
diff --git a/lundump.c b/lundump.c
index 5c0e94d6..8f2a490c 100644
--- a/lundump.c
+++ b/lundump.c
@@ -198,12 +198,11 @@ static void LoadUpvalues (LoadState *S, Proto *f) {
198 n = LoadInt(S); 198 n = LoadInt(S);
199 f->upvalues = luaM_newvectorchecked(S->L, n, Upvaldesc); 199 f->upvalues = luaM_newvectorchecked(S->L, n, Upvaldesc);
200 f->sizeupvalues = n; 200 f->sizeupvalues = n;
201 for (i = 0; i < n; i++)
202 f->upvalues[i].name = NULL;
203 for (i = 0; i < n; i++) { 201 for (i = 0; i < n; i++) {
202 f->upvalues[i].name = NULL;
204 f->upvalues[i].instack = LoadByte(S); 203 f->upvalues[i].instack = LoadByte(S);
205 f->upvalues[i].idx = LoadByte(S); 204 f->upvalues[i].idx = LoadByte(S);
206 f->upvalues[i].ro = LoadByte(S); 205 f->upvalues[i].kind = LoadByte(S);
207 } 206 }
208} 207}
209 208
diff --git a/manual/manual.of b/manual/manual.of
index 136e9022..61fcdaa3 100644
--- a/manual/manual.of
+++ b/manual/manual.of
@@ -223,7 +223,7 @@ In Lua, the global variable @Lid{_G} is initialized with this same value.
223so changing its value will affect only your own code.) 223so changing its value will affect only your own code.)
224 224
225When Lua loads a chunk, 225When Lua loads a chunk,
226the default value for its @id{_ENV} upvalue 226the default value for its @id{_ENV} variable
227is the global environment @seeF{load}. 227is the global environment @seeF{load}.
228Therefore, by default, 228Therefore, by default,
229free names in Lua code refer to entries in the global environment 229free names in Lua code refer to entries in the global environment
@@ -233,7 +233,7 @@ and some functions there operate on that environment.
233You can use @Lid{load} (or @Lid{loadfile}) 233You can use @Lid{load} (or @Lid{loadfile})
234to load a chunk with a different environment. 234to load a chunk with a different environment.
235(In C, you have to load the chunk and then change the value 235(In C, you have to load the chunk and then change the value
236of its first upvalue.) 236of its first upvalue; see @See{lua_setupvalue}.)
237 237
238} 238}
239 239
@@ -1224,7 +1224,7 @@ As such, chunks can define local variables,
1224receive arguments, and return values. 1224receive arguments, and return values.
1225Moreover, such anonymous function is compiled as in the 1225Moreover, such anonymous function is compiled as in the
1226scope of an external local variable called @id{_ENV} @see{globalenv}. 1226scope of an external local variable called @id{_ENV} @see{globalenv}.
1227The resulting function always has @id{_ENV} as its only upvalue, 1227The resulting function always has @id{_ENV} as its only external variable,
1228even if it does not use that variable. 1228even if it does not use that variable.
1229 1229
1230A chunk can be stored in a file or in a string inside the host program. 1230A chunk can be stored in a file or in a string inside the host program.
@@ -2241,8 +2241,8 @@ and so the second @id{x} refers to the outside variable.
2241Because of the @x{lexical scoping} rules, 2241Because of the @x{lexical scoping} rules,
2242local variables can be freely accessed by functions 2242local variables can be freely accessed by functions
2243defined inside their scope. 2243defined inside their scope.
2244A local variable used by an inner function is called 2244A local variable used by an inner function is called an @def{upvalue}
2245an @def{upvalue}, or @emphx{external local variable}, 2245(or @emphx{external local variable}, or simply @emphx{external variable})
2246inside the inner function. 2246inside the inner function.
2247 2247
2248Notice that each execution of a @Rw{local} statement 2248Notice that each execution of a @Rw{local} statement
@@ -4765,11 +4765,7 @@ and returns its name.
4765Returns @id{NULL} (and pushes nothing) 4765Returns @id{NULL} (and pushes nothing)
4766when the index @id{n} is greater than the number of upvalues. 4766when the index @id{n} is greater than the number of upvalues.
4767 4767
4768For @N{C functions}, this function uses the empty string @T{""} 4768See @Lid{debug.getupvalue} for more information about upvalues.
4769as a name for all upvalues.
4770(For Lua functions,
4771upvalues are the external local variables that the function uses,
4772and that are consequently included in its closure.)
4773 4769
4774} 4770}
4775 4771
@@ -8485,6 +8481,8 @@ The first parameter or local variable has @N{index 1}, and so on,
8485following the order that they are declared in the code, 8481following the order that they are declared in the code,
8486counting only the variables that are active 8482counting only the variables that are active
8487in the current scope of the function. 8483in the current scope of the function.
8484Compile-time constants may not appear in this listing,
8485if they were optimized away by the compiler.
8488Negative indices refer to vararg arguments; 8486Negative indices refer to vararg arguments;
8489@num{-1} is the first vararg argument. 8487@num{-1} is the first vararg argument.
8490The function returns @nil if there is no variable with the given index, 8488The function returns @nil if there is no variable with the given index,
@@ -8520,8 +8518,15 @@ This function returns the name and the value of the upvalue
8520with index @id{up} of the function @id{f}. 8518with index @id{up} of the function @id{f}.
8521The function returns @nil if there is no upvalue with the given index. 8519The function returns @nil if there is no upvalue with the given index.
8522 8520
8523Variable names starting with @Char{(} (open parenthesis) @C{)} 8521(For Lua functions,
8524represent variables with no known names 8522upvalues are the external local variables that the function uses,
8523and that are consequently included in its closure.)
8524
8525For @N{C functions}, this function uses the empty string @T{""}
8526as a name for all upvalues.
8527
8528Variable name @Char{?} (interrogation mark)
8529represents variables with no known names
8525(variables from chunks saved without debug information). 8530(variables from chunks saved without debug information).
8526 8531
8527} 8532}
@@ -8626,6 +8631,8 @@ The function returns @nil if there is no upvalue
8626with the given index. 8631with the given index.
8627Otherwise, it returns the name of the upvalue. 8632Otherwise, it returns the name of the upvalue.
8628 8633
8634See @Lid{debug.getupvalue} for more information about upvalues.
8635
8629} 8636}
8630 8637
8631@LibEntry{debug.setuservalue (udata, value, n)| 8638@LibEntry{debug.setuservalue (udata, value, n)|
diff --git a/testes/code.lua b/testes/code.lua
index 128ca2cb..49d682f8 100644
--- a/testes/code.lua
+++ b/testes/code.lua
@@ -7,6 +7,22 @@ if T==nil then
7end 7end
8print "testing code generation and optimizations" 8print "testing code generation and optimizations"
9 9
10-- to test constant propagation
11local <const> k0 = 0
12local <const> k1 = 1
13local <const> k3 = 3
14local <const> k6 = k3 + (k3 << k0)
15local <const> kFF0 = 0xFF0
16local <const> k3_78 = 3.78
17local <const> x, <const> k3_78_4 = 10, k3_78 / 4
18assert(x == 10)
19
20local <const> kx = "x"
21
22local <const> kTrue = true
23local <const> kFalse = false
24
25local <const> kNil = nil
10 26
11-- this code gave an error for the code checker 27-- this code gave an error for the code checker
12do 28do
@@ -27,12 +43,12 @@ end
27 43
28local function foo () 44local function foo ()
29 local a 45 local a
30 a = 3; 46 a = k3;
31 a = 0; a = 0.0; a = -7 + 7 47 a = 0; a = 0.0; a = -7 + 7
32 a = 3.78/4; a = 3.78/4 48 a = k3_78/4; a = k3_78_4
33 a = -3.78/4; a = 3.78/4; a = -3.78/4 49 a = -k3_78/4; a = k3_78/4; a = -3.78/4
34 a = -3.79/4; a = 0.0; a = -0; 50 a = -3.79/4; a = 0.0; a = -0;
35 a = 3; a = 3.0; a = 3; a = 3.0 51 a = k3; a = 3.0; a = 3; a = 3.0
36end 52end
37 53
38checkKlist(foo, {3.78/4, -3.78/4, -3.79/4}) 54checkKlist(foo, {3.78/4, -3.78/4, -3.79/4})
@@ -86,10 +102,11 @@ end, 'CLOSURE', 'NEWTABLE', 'GETTABUP', 'CALL', 'SETLIST', 'CALL', 'RETURN')
86 102
87-- sequence of LOADNILs 103-- sequence of LOADNILs
88check(function () 104check(function ()
105 local <const> kNil = nil
89 local a,b,c 106 local a,b,c
90 local d; local e; 107 local d; local e;
91 local f,g,h; 108 local f,g,h;
92 d = nil; d=nil; b=nil; a=nil; c=nil; 109 d = nil; d=nil; b=nil; a=kNil; c=nil;
93end, 'LOADNIL', 'RETURN0') 110end, 'LOADNIL', 'RETURN0')
94 111
95check(function () 112check(function ()
@@ -109,7 +126,7 @@ check (function (a,b,c) return a end, 'RETURN1')
109 126
110 127
111-- infinite loops 128-- infinite loops
112check(function () while true do local a = -1 end end, 129check(function () while kTrue do local a = -1 end end,
113'LOADI', 'JMP', 'RETURN0') 130'LOADI', 'JMP', 'RETURN0')
114 131
115check(function () while 1 do local a = -1 end end, 132check(function () while 1 do local a = -1 end end,
@@ -125,9 +142,9 @@ check(function (a,b,c,d) return a..b..c..d end,
125 142
126-- not 143-- not
127check(function () return not not nil end, 'LOADBOOL', 'RETURN1') 144check(function () return not not nil end, 'LOADBOOL', 'RETURN1')
128check(function () return not not false end, 'LOADBOOL', 'RETURN1') 145check(function () return not not kFalse end, 'LOADBOOL', 'RETURN1')
129check(function () return not not true end, 'LOADBOOL', 'RETURN1') 146check(function () return not not true end, 'LOADBOOL', 'RETURN1')
130check(function () return not not 1 end, 'LOADBOOL', 'RETURN1') 147check(function () return not not k3 end, 'LOADBOOL', 'RETURN1')
131 148
132-- direct access to locals 149-- direct access to locals
133check(function () 150check(function ()
@@ -144,7 +161,8 @@ end,
144-- direct access to constants 161-- direct access to constants
145check(function () 162check(function ()
146 local a,b 163 local a,b
147 a.x = 3.2 164 local c = kNil
165 a[kx] = 3.2
148 a.x = b 166 a.x = b
149 a[b] = 'x' 167 a[b] = 'x'
150end, 168end,
@@ -152,8 +170,9 @@ end,
152 170
153-- "get/set table" with numeric indices 171-- "get/set table" with numeric indices
154check(function (a) 172check(function (a)
173 local <const> k255 = 255
155 a[1] = a[100] 174 a[1] = a[100]
156 a[255] = a[256] 175 a[k255] = a[256]
157 a[256] = 5 176 a[256] = 5
158end, 177end,
159 'GETI', 'SETI', 178 'GETI', 'SETI',
@@ -170,7 +189,7 @@ end,
170 189
171check(function () 190check(function ()
172 local a,b 191 local a,b
173 a[true] = false 192 a[kTrue] = false
174end, 193end,
175 'LOADNIL', 'LOADBOOL', 'SETTABLE', 'RETURN0') 194 'LOADNIL', 'LOADBOOL', 'SETTABLE', 'RETURN0')
176 195
@@ -238,37 +257,39 @@ local function checkF (func, val)
238end 257end
239 258
240checkF(function () return 0.0 end, 0.0) 259checkF(function () return 0.0 end, 0.0)
241checkI(function () return 0 end, 0) 260checkI(function () return k0 end, 0)
242checkI(function () return -0//1 end, 0) 261checkI(function () return -k0//1 end, 0)
243checkK(function () return 3^-1 end, 1/3) 262checkK(function () return 3^-1 end, 1/3)
244checkK(function () return (1 + 1)^(50 + 50) end, 2^100) 263checkK(function () return (1 + 1)^(50 + 50) end, 2^100)
245checkK(function () return (-2)^(31 - 2) end, -0x20000000 + 0.0) 264checkK(function () return (-2)^(31 - 2) end, -0x20000000 + 0.0)
246checkF(function () return (-3^0 + 5) // 3.0 end, 1.0) 265checkF(function () return (-k3^0 + 5) // 3.0 end, 1.0)
247checkI(function () return -3 % 5 end, 2) 266checkI(function () return -k3 % 5 end, 2)
248checkF(function () return -((2.0^8 + -(-1)) % 8)/2 * 4 - 3 end, -5.0) 267checkF(function () return -((2.0^8 + -(-1)) % 8)/2 * 4 - 3 end, -5.0)
249checkF(function () return -((2^8 + -(-1)) % 8)//2 * 4 - 3 end, -7.0) 268checkF(function () return -((2^8 + -(-1)) % 8)//2 * 4 - 3 end, -7.0)
250checkI(function () return 0xF0.0 | 0xCC.0 ~ 0xAA & 0xFD end, 0xF4) 269checkI(function () return 0xF0.0 | 0xCC.0 ~ 0xAA & 0xFD end, 0xF4)
251checkI(function () return ~(~0xFF0 | 0xFF0) end, 0) 270checkI(function () return ~(~kFF0 | kFF0) end, 0)
252checkI(function () return ~~-1024.0 end, -1024) 271checkI(function () return ~~-1024.0 end, -1024)
253checkI(function () return ((100 << 6) << -4) >> 2 end, 100) 272checkI(function () return ((100 << k6) << -4) >> 2 end, 100)
254 273
255-- borders around MAXARG_sBx ((((1 << 17) - 1) >> 1) == 65535) 274-- borders around MAXARG_sBx ((((1 << 17) - 1) >> 1) == 65535)
256local a = 17; local sbx = ((1 << a) - 1) >> 1 -- avoid folding 275local a = 17; local sbx = ((1 << a) - 1) >> 1 -- avoid folding
257checkI(function () return 65535 end, sbx) 276local <const> border = 65535
258checkI(function () return -65535 end, -sbx) 277checkI(function () return border end, sbx)
259checkI(function () return 65536 end, sbx + 1) 278checkI(function () return -border end, -sbx)
260checkK(function () return 65537 end, sbx + 2) 279checkI(function () return border + 1 end, sbx + 1)
261checkK(function () return -65536 end, -(sbx + 1)) 280checkK(function () return border + 2 end, sbx + 2)
281checkK(function () return -(border + 1) end, -(sbx + 1))
262 282
263checkF(function () return 65535.0 end, sbx + 0.0) 283local <const> border = 65535.0
264checkF(function () return -65535.0 end, -sbx + 0.0) 284checkF(function () return border end, sbx + 0.0)
265checkF(function () return 65536.0 end, (sbx + 1.0)) 285checkF(function () return -border end, -sbx + 0.0)
266checkK(function () return 65537.0 end, (sbx + 2.0)) 286checkF(function () return border + 1 end, (sbx + 1.0))
267checkK(function () return -65536.0 end, -(sbx + 1.0)) 287checkK(function () return border + 2 end, (sbx + 2.0))
288checkK(function () return -(border + 1) end, -(sbx + 1.0))
268 289
269 290
270-- immediate operands 291-- immediate operands
271checkR(function (x) return x + 1 end, 10, 11, 'ADDI', 'RETURN1') 292checkR(function (x) return x + k1 end, 10, 11, 'ADDI', 'RETURN1')
272checkR(function (x) return 128 + x end, 0.0, 128.0, 'ADDI', 'RETURN1') 293checkR(function (x) return 128 + x end, 0.0, 128.0, 'ADDI', 'RETURN1')
273checkR(function (x) return x * -127 end, -1.0, 127.0, 'MULI', 'RETURN1') 294checkR(function (x) return x * -127 end, -1.0, 127.0, 'MULI', 'RETURN1')
274checkR(function (x) return 20 * x end, 2, 40, 'MULI', 'RETURN1') 295checkR(function (x) return 20 * x end, 2, 40, 'MULI', 'RETURN1')
@@ -276,7 +297,7 @@ checkR(function (x) return x ^ -2 end, 2, 0.25, 'POWI', 'RETURN1')
276checkR(function (x) return x / 40 end, 40, 1.0, 'DIVI', 'RETURN1') 297checkR(function (x) return x / 40 end, 40, 1.0, 'DIVI', 'RETURN1')
277checkR(function (x) return x // 1 end, 10.0, 10.0, 'IDIVI', 'RETURN1') 298checkR(function (x) return x // 1 end, 10.0, 10.0, 'IDIVI', 'RETURN1')
278checkR(function (x) return x % (100 - 10) end, 91, 1, 'MODI', 'RETURN1') 299checkR(function (x) return x % (100 - 10) end, 91, 1, 'MODI', 'RETURN1')
279checkR(function (x) return 1 << x end, 3, 8, 'SHLI', 'RETURN1') 300checkR(function (x) return k1 << x end, 3, 8, 'SHLI', 'RETURN1')
280checkR(function (x) return x << 2 end, 10, 40, 'SHRI', 'RETURN1') 301checkR(function (x) return x << 2 end, 10, 40, 'SHRI', 'RETURN1')
281checkR(function (x) return x >> 2 end, 8, 2, 'SHRI', 'RETURN1') 302checkR(function (x) return x >> 2 end, 8, 2, 'SHRI', 'RETURN1')
282checkR(function (x) return x & 1 end, 9, 1, 'BANDK', 'RETURN1') 303checkR(function (x) return x & 1 end, 9, 1, 'BANDK', 'RETURN1')
@@ -295,7 +316,7 @@ checkR(function (x) return x % (100.0 - 10) end, 91, 1.0, 'MODK', 'RETURN1')
295 316
296-- no foldings (and immediate operands) 317-- no foldings (and immediate operands)
297check(function () return -0.0 end, 'LOADF', 'UNM', 'RETURN1') 318check(function () return -0.0 end, 'LOADF', 'UNM', 'RETURN1')
298check(function () return 3/0 end, 'LOADI', 'DIVI', 'RETURN1') 319check(function () return k3/0 end, 'LOADI', 'DIVI', 'RETURN1')
299check(function () return 0%0 end, 'LOADI', 'MODI', 'RETURN1') 320check(function () return 0%0 end, 'LOADI', 'MODI', 'RETURN1')
300check(function () return -4//0 end, 'LOADI', 'IDIVI', 'RETURN1') 321check(function () return -4//0 end, 'LOADI', 'IDIVI', 'RETURN1')
301check(function (x) return x >> 2.0 end, 'LOADF', 'SHR', 'RETURN1') 322check(function (x) return x >> 2.0 end, 'LOADF', 'SHR', 'RETURN1')
@@ -335,7 +356,7 @@ end,
335 356
336do -- tests for table access in upvalues 357do -- tests for table access in upvalues
337 local t 358 local t
338 check(function () t.x = t.y end, 'GETTABUP', 'SETTABUP') 359 check(function () t[kx] = t.y end, 'GETTABUP', 'SETTABUP')
339 check(function (a) t[a()] = t[a()] end, 360 check(function (a) t[a()] = t[a()] end,
340 'MOVE', 'CALL', 'GETUPVAL', 'MOVE', 'CALL', 361 'MOVE', 'CALL', 'GETUPVAL', 'MOVE', 'CALL',
341 'GETUPVAL', 'GETTABLE', 'SETTABLE') 362 'GETUPVAL', 'GETTABLE', 'SETTABLE')
@@ -379,6 +400,12 @@ function (a)
379end 400end
380) 401)
381 402
403checkequal(function () return 6 or true or nil end,
404 function () return k6 or kTrue or kNil end)
405
406checkequal(function () return 6 and true or nil end,
407 function () return k6 and kTrue or kNil end)
408
382 409
383print 'OK' 410print 'OK'
384 411
diff --git a/testes/constructs.lua b/testes/constructs.lua
index fe4db2cb..8a549e10 100644
--- a/testes/constructs.lua
+++ b/testes/constructs.lua
@@ -287,7 +287,7 @@ a,b = F(nil)==nil; assert(a == true and b == nil)
287------------------------------------------------------------------ 287------------------------------------------------------------------
288 288
289-- sometimes will be 0, sometimes will not... 289-- sometimes will be 0, sometimes will not...
290_ENV.GLOB1 = math.floor(os.time()) % 2 290_ENV.GLOB1 = math.random(0, 1)
291 291
292-- basic expressions with their respective values 292-- basic expressions with their respective values
293local basiccases = { 293local basiccases = {
@@ -298,6 +298,26 @@ local basiccases = {
298 {"(0==_ENV.GLOB1)", 0 == _ENV.GLOB1}, 298 {"(0==_ENV.GLOB1)", 0 == _ENV.GLOB1},
299} 299}
300 300
301local prog
302
303if _ENV.GLOB1 == 0 then
304 basiccases[2][1] = "F" -- constant false
305
306 prog = [[
307 local <const> F = false
308 if %s then IX = true end
309 return %s
310]]
311else
312 basiccases[4][1] = "k10" -- constant 10
313
314 prog = [[
315 local <const> k10 = 10
316 if %s then IX = true end
317 return %s
318 ]]
319end
320
301print('testing short-circuit optimizations (' .. _ENV.GLOB1 .. ')') 321print('testing short-circuit optimizations (' .. _ENV.GLOB1 .. ')')
302 322
303 323
@@ -337,8 +357,6 @@ cases[1] = basiccases
337for i = 2, level do cases[i] = createcases(i) end 357for i = 2, level do cases[i] = createcases(i) end
338print("+") 358print("+")
339 359
340local prog = [[if %s then IX = true end; return %s]]
341
342local i = 0 360local i = 0
343for n = 1, level do 361for n = 1, level do
344 for _, v in pairs(cases[n]) do 362 for _, v in pairs(cases[n]) do
diff --git a/testes/locals.lua b/testes/locals.lua
index 0de00a98..1b82dd7f 100644
--- a/testes/locals.lua
+++ b/testes/locals.lua
@@ -324,7 +324,7 @@ do
324 324
325 -- errors due to non-closable values 325 -- errors due to non-closable values
326 local function foo () 326 local function foo ()
327 local <toclose> x = 34 327 local <toclose> x = {}
328 end 328 end
329 local stat, msg = pcall(foo) 329 local stat, msg = pcall(foo)
330 assert(not stat and string.find(msg, "variable 'x'")) 330 assert(not stat and string.find(msg, "variable 'x'"))
diff --git a/testes/math.lua b/testes/math.lua
index c45a91ad..befce12e 100644
--- a/testes/math.lua
+++ b/testes/math.lua
@@ -270,7 +270,7 @@ else
270end 270end
271 271
272do 272do
273 local NaN = 0/0 273 local <const> NaN = 0/0
274 assert(not (NaN < 0)) 274 assert(not (NaN < 0))
275 assert(not (NaN > minint)) 275 assert(not (NaN > minint))
276 assert(not (NaN <= -9)) 276 assert(not (NaN <= -9))
@@ -767,7 +767,8 @@ assert(a == '10' and b == '20')
767 767
768do 768do
769 print("testing -0 and NaN") 769 print("testing -0 and NaN")
770 local mz, z = -0.0, 0.0 770 local <const> mz = -0.0
771 local <const> z = 0.0
771 assert(mz == z) 772 assert(mz == z)
772 assert(1/mz < 0 and 0 < 1/z) 773 assert(1/mz < 0 and 0 < 1/z)
773 local a = {[mz] = 1} 774 local a = {[mz] = 1}
@@ -775,17 +776,18 @@ do
775 a[z] = 2 776 a[z] = 2
776 assert(a[z] == 2 and a[mz] == 2) 777 assert(a[z] == 2 and a[mz] == 2)
777 local inf = math.huge * 2 + 1 778 local inf = math.huge * 2 + 1
778 mz, z = -1/inf, 1/inf 779 local <const> mz = -1/inf
780 local <const> z = 1/inf
779 assert(mz == z) 781 assert(mz == z)
780 assert(1/mz < 0 and 0 < 1/z) 782 assert(1/mz < 0 and 0 < 1/z)
781 local NaN = inf - inf 783 local <const> NaN = inf - inf
782 assert(NaN ~= NaN) 784 assert(NaN ~= NaN)
783 assert(not (NaN < NaN)) 785 assert(not (NaN < NaN))
784 assert(not (NaN <= NaN)) 786 assert(not (NaN <= NaN))
785 assert(not (NaN > NaN)) 787 assert(not (NaN > NaN))
786 assert(not (NaN >= NaN)) 788 assert(not (NaN >= NaN))
787 assert(not (0 < NaN) and not (NaN < 0)) 789 assert(not (0 < NaN) and not (NaN < 0))
788 local NaN1 = 0/0 790 local <const> NaN1 = 0/0
789 assert(NaN ~= NaN1 and not (NaN <= NaN1) and not (NaN1 <= NaN)) 791 assert(NaN ~= NaN1 and not (NaN <= NaN1) and not (NaN1 <= NaN))
790 local a = {} 792 local a = {}
791 assert(not pcall(rawset, a, NaN, 1)) 793 assert(not pcall(rawset, a, NaN, 1))
@@ -814,8 +816,8 @@ end
814-- the first call after seed 1007 should return 0x7a7040a5a323c9d6 816-- the first call after seed 1007 should return 0x7a7040a5a323c9d6
815do 817do
816 -- all computations assume at most 32-bit integers 818 -- all computations assume at most 32-bit integers
817 local h = 0x7a7040a5 -- higher half 819 local <const> h = 0x7a7040a5 -- higher half
818 local l = 0xa323c9d6 -- lower half 820 local <const> l = 0xa323c9d6 -- lower half
819 821
820 math.randomseed(1007) 822 math.randomseed(1007)
821 -- get the low 'intbits' of the 64-bit expected result 823 -- get the low 'intbits' of the 64-bit expected result