diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-03-19 10:53:18 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-03-19 10:53:18 -0300 |
commit | 9b37a4695ebf50b37b5b4fb279ae948f23b5b6a0 (patch) | |
tree | 2a6b0f6c1c2eb962bb383175eb0a67ea81a4564d /lparser.c | |
parent | 1e0c73d5b643707335b06abd2546a83d9439d14c (diff) | |
download | lua-9b37a4695ebf50b37b5b4fb279ae948f23b5b6a0.tar.gz lua-9b37a4695ebf50b37b5b4fb279ae948f23b5b6a0.tar.bz2 lua-9b37a4695ebf50b37b5b4fb279ae948f23b5b6a0.zip |
New semantics for the integer 'for' loop
The numerical 'for' loop over integers now uses a precomputed counter
to control its number of iteractions. This change eliminates several
weird cases caused by overflows (wrap-around) in the control variable.
(It also ensures that every integer loop halts.)
Also, the special opcodes for the usual case of step==1 were removed.
(The new code is already somewhat complex for the usual case,
but efficient.)
Diffstat (limited to 'lparser.c')
-rw-r--r-- | lparser.c | 42 |
1 files changed, 16 insertions, 26 deletions
@@ -1371,18 +1371,14 @@ static void repeatstat (LexState *ls, int line) { | |||
1371 | 1371 | ||
1372 | /* | 1372 | /* |
1373 | ** Read an expression and generate code to put its results in next | 1373 | ** Read an expression and generate code to put its results in next |
1374 | ** stack slot. Return true if expression is a constant integer and, | 1374 | ** stack slot. |
1375 | ** if 'i' is not-zero, its value is equal to 'i'. | ||
1376 | ** | 1375 | ** |
1377 | */ | 1376 | */ |
1378 | static int exp1 (LexState *ls, int i) { | 1377 | static void exp1 (LexState *ls) { |
1379 | expdesc e; | 1378 | expdesc e; |
1380 | int res; | ||
1381 | expr(ls, &e); | 1379 | expr(ls, &e); |
1382 | res = luaK_isKint(&e) && (i == 0 || i == e.u.ival); | ||
1383 | luaK_exp2nextreg(ls->fs, &e); | 1380 | luaK_exp2nextreg(ls->fs, &e); |
1384 | lua_assert(e.k == VNONRELOC); | 1381 | lua_assert(e.k == VNONRELOC); |
1385 | return res; | ||
1386 | } | 1382 | } |
1387 | 1383 | ||
1388 | 1384 | ||
@@ -1403,31 +1399,29 @@ static void fixforjump (FuncState *fs, int pc, int dest, int back) { | |||
1403 | 1399 | ||
1404 | 1400 | ||
1405 | /* | 1401 | /* |
1406 | ** Generate code for a 'for' loop. 'kind' can be zero (a common for | 1402 | ** Generate code for a 'for' loop. |
1407 | ** loop), one (a basic for loop, with integer values and increment of | ||
1408 | ** 1), or two (a generic for loop). | ||
1409 | */ | 1403 | */ |
1410 | static void forbody (LexState *ls, int base, int line, int nvars, int kind) { | 1404 | static void forbody (LexState *ls, int base, int line, int nvars, int isgen) { |
1411 | /* forbody -> DO block */ | 1405 | /* forbody -> DO block */ |
1412 | static OpCode forprep[3] = {OP_FORPREP, OP_FORPREP1, OP_TFORPREP}; | 1406 | static OpCode forprep[2] = {OP_FORPREP, OP_TFORPREP}; |
1413 | static OpCode forloop[3] = {OP_FORLOOP, OP_FORLOOP1, OP_TFORLOOP}; | 1407 | static OpCode forloop[2] = {OP_FORLOOP, OP_TFORLOOP}; |
1414 | BlockCnt bl; | 1408 | BlockCnt bl; |
1415 | FuncState *fs = ls->fs; | 1409 | FuncState *fs = ls->fs; |
1416 | int prep, endfor; | 1410 | int prep, endfor; |
1417 | checknext(ls, TK_DO); | 1411 | checknext(ls, TK_DO); |
1418 | prep = luaK_codeABx(fs, forprep[kind], base, 0); | 1412 | prep = luaK_codeABx(fs, forprep[isgen], base, 0); |
1419 | enterblock(fs, &bl, 0); /* scope for declared variables */ | 1413 | enterblock(fs, &bl, 0); /* scope for declared variables */ |
1420 | adjustlocalvars(ls, nvars); | 1414 | adjustlocalvars(ls, nvars); |
1421 | luaK_reserveregs(fs, nvars); | 1415 | luaK_reserveregs(fs, nvars); |
1422 | block(ls); | 1416 | block(ls); |
1423 | leaveblock(fs); /* end of scope for declared variables */ | 1417 | leaveblock(fs); /* end of scope for declared variables */ |
1424 | fixforjump(fs, prep, luaK_getlabel(fs), 0); | 1418 | fixforjump(fs, prep, luaK_getlabel(fs), 0); |
1425 | if (kind == 2) { /* generic for? */ | 1419 | if (isgen) { /* generic for? */ |
1426 | luaK_codeABC(fs, OP_TFORCALL, base, 0, nvars); | 1420 | luaK_codeABC(fs, OP_TFORCALL, base, 0, nvars); |
1427 | luaK_fixline(fs, line); | 1421 | luaK_fixline(fs, line); |
1428 | base += 2; /* base for 'OP_TFORLOOP' (skips function and state) */ | 1422 | base += 2; /* base for 'OP_TFORLOOP' (skips function and state) */ |
1429 | } | 1423 | } |
1430 | endfor = luaK_codeABx(fs, forloop[kind], base, 0); | 1424 | endfor = luaK_codeABx(fs, forloop[isgen], base, 0); |
1431 | fixforjump(fs, endfor, prep + 1, 1); | 1425 | fixforjump(fs, endfor, prep + 1, 1); |
1432 | luaK_fixline(fs, line); | 1426 | luaK_fixline(fs, line); |
1433 | } | 1427 | } |
@@ -1437,26 +1431,22 @@ static void fornum (LexState *ls, TString *varname, int line) { | |||
1437 | /* fornum -> NAME = exp,exp[,exp] forbody */ | 1431 | /* fornum -> NAME = exp,exp[,exp] forbody */ |
1438 | FuncState *fs = ls->fs; | 1432 | FuncState *fs = ls->fs; |
1439 | int base = fs->freereg; | 1433 | int base = fs->freereg; |
1440 | int basicfor = 1; /* true if it is a "basic" 'for' (integer + 1) */ | ||
1441 | new_localvarliteral(ls, "(for index)"); | 1434 | new_localvarliteral(ls, "(for index)"); |
1442 | new_localvarliteral(ls, "(for limit)"); | 1435 | new_localvarliteral(ls, "(for limit)"); |
1443 | new_localvarliteral(ls, "(for step)"); | 1436 | new_localvarliteral(ls, "(for step)"); |
1444 | new_localvar(ls, varname); | 1437 | new_localvar(ls, varname); |
1445 | checknext(ls, '='); | 1438 | checknext(ls, '='); |
1446 | if (!exp1(ls, 0)) /* initial value not an integer? */ | 1439 | exp1(ls); /* initial value */ |
1447 | basicfor = 0; /* not a basic 'for' */ | ||
1448 | checknext(ls, ','); | 1440 | checknext(ls, ','); |
1449 | exp1(ls, 0); /* limit */ | 1441 | exp1(ls); /* limit */ |
1450 | if (testnext(ls, ',')) { | 1442 | if (testnext(ls, ',')) |
1451 | if (!exp1(ls, 1)) /* optional step not 1? */ | 1443 | exp1(ls); /* optional step */ |
1452 | basicfor = 0; /* not a basic 'for' */ | ||
1453 | } | ||
1454 | else { /* default step = 1 */ | 1444 | else { /* default step = 1 */ |
1455 | luaK_int(fs, fs->freereg, 1); | 1445 | luaK_int(fs, fs->freereg, 1); |
1456 | luaK_reserveregs(fs, 1); | 1446 | luaK_reserveregs(fs, 1); |
1457 | } | 1447 | } |
1458 | adjustlocalvars(ls, 3); /* control variables */ | 1448 | adjustlocalvars(ls, 3); /* control variables */ |
1459 | forbody(ls, base, line, 1, basicfor); | 1449 | forbody(ls, base, line, 1, 0); |
1460 | } | 1450 | } |
1461 | 1451 | ||
1462 | 1452 | ||
@@ -1484,7 +1474,7 @@ static void forlist (LexState *ls, TString *indexname) { | |||
1484 | adjust_assign(ls, 4, explist(ls, &e), &e); | 1474 | adjust_assign(ls, 4, explist(ls, &e), &e); |
1485 | adjustlocalvars(ls, 4); /* control variables */ | 1475 | adjustlocalvars(ls, 4); /* control variables */ |
1486 | luaK_checkstack(fs, 3); /* extra space to call generator */ | 1476 | luaK_checkstack(fs, 3); /* extra space to call generator */ |
1487 | forbody(ls, base, line, nvars - 4, 2); | 1477 | forbody(ls, base, line, nvars - 4, 1); |
1488 | } | 1478 | } |
1489 | 1479 | ||
1490 | 1480 | ||
@@ -1633,7 +1623,7 @@ static void tocloselocalstat (LexState *ls) { | |||
1633 | luaO_pushfstring(ls->L, "unknown attribute '%s'", getstr(attr))); | 1623 | luaO_pushfstring(ls->L, "unknown attribute '%s'", getstr(attr))); |
1634 | new_localvar(ls, str_checkname(ls)); | 1624 | new_localvar(ls, str_checkname(ls)); |
1635 | checknext(ls, '='); | 1625 | checknext(ls, '='); |
1636 | exp1(ls, 0); | 1626 | exp1(ls); |
1637 | markupval(fs, fs->nactvar); | 1627 | markupval(fs, fs->nactvar); |
1638 | fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */ | 1628 | fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */ |
1639 | adjustlocalvars(ls, 1); | 1629 | adjustlocalvars(ls, 1); |