diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2020-11-11 14:41:41 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2020-11-11 14:41:41 -0300 |
| commit | ab1aca94e83d2eff1605ea1854df023c814cef21 (patch) | |
| tree | 16b87253f000cb0052133bf2e1ede3d4b2b730ef | |
| parent | d28265256110a0c5437247d443ddedc2a7aab116 (diff) | |
| download | lua-ab1aca94e83d2eff1605ea1854df023c814cef21.tar.gz lua-ab1aca94e83d2eff1605ea1854df023c814cef21.tar.bz2 lua-ab1aca94e83d2eff1605ea1854df023c814cef21.zip | |
Removed optimization for «if ... then goto»
That optimization was too complex and caused some weird traces when
debugging. The more common case «if ... then break» was kept.
| -rw-r--r-- | lparser.c | 50 | ||||
| -rw-r--r-- | testes/code.lua | 22 |
2 files changed, 6 insertions, 66 deletions
| @@ -1623,59 +1623,21 @@ static void forstat (LexState *ls, int line) { | |||
| 1623 | } | 1623 | } |
| 1624 | 1624 | ||
| 1625 | 1625 | ||
| 1626 | /* | ||
| 1627 | ** Check whether next instruction is a single jump (a 'break', a 'goto' | ||
| 1628 | ** to a forward label, or a 'goto' to a backward label with no variable | ||
| 1629 | ** to close). If so, set the name of the 'label' it is jumping to | ||
| 1630 | ** ("break" for a 'break') or to where it is jumping to ('target') and | ||
| 1631 | ** return true. If not a single jump, leave input unchanged, to be | ||
| 1632 | ** handled as a regular statement. | ||
| 1633 | */ | ||
| 1634 | static int issinglejump (LexState *ls, TString **label, int *target) { | ||
| 1635 | if (testnext(ls, TK_BREAK)) { /* a break? */ | ||
| 1636 | *label = luaS_newliteral(ls->L, "break"); | ||
| 1637 | return 1; | ||
| 1638 | } | ||
| 1639 | else if (ls->t.token != TK_GOTO || luaX_lookahead(ls) != TK_NAME) | ||
| 1640 | return 0; /* not a valid goto */ | ||
| 1641 | else { | ||
| 1642 | TString *lname = ls->lookahead.seminfo.ts; /* label's id */ | ||
| 1643 | Labeldesc *lb = findlabel(ls, lname); | ||
| 1644 | if (lb) { /* a backward jump? */ | ||
| 1645 | /* does it need to close variables? */ | ||
| 1646 | if (luaY_nvarstack(ls->fs) > stacklevel(ls->fs, lb->nactvar)) | ||
| 1647 | return 0; /* not a single jump; cannot optimize */ | ||
| 1648 | *target = lb->pc; | ||
| 1649 | } | ||
| 1650 | else /* jump forward */ | ||
| 1651 | *label = lname; | ||
| 1652 | luaX_next(ls); /* skip goto */ | ||
| 1653 | luaX_next(ls); /* skip name */ | ||
| 1654 | return 1; | ||
| 1655 | } | ||
| 1656 | } | ||
| 1657 | |||
| 1658 | |||
| 1659 | static void test_then_block (LexState *ls, int *escapelist) { | 1626 | static void test_then_block (LexState *ls, int *escapelist) { |
| 1660 | /* test_then_block -> [IF | ELSEIF] cond THEN block */ | 1627 | /* test_then_block -> [IF | ELSEIF] cond THEN block */ |
| 1661 | BlockCnt bl; | 1628 | BlockCnt bl; |
| 1662 | int line; | ||
| 1663 | FuncState *fs = ls->fs; | 1629 | FuncState *fs = ls->fs; |
| 1664 | TString *jlb = NULL; | ||
| 1665 | int target = NO_JUMP; | ||
| 1666 | expdesc v; | 1630 | expdesc v; |
| 1667 | int jf; /* instruction to skip 'then' code (if condition is false) */ | 1631 | int jf; /* instruction to skip 'then' code (if condition is false) */ |
| 1668 | luaX_next(ls); /* skip IF or ELSEIF */ | 1632 | luaX_next(ls); /* skip IF or ELSEIF */ |
| 1669 | expr(ls, &v); /* read condition */ | 1633 | expr(ls, &v); /* read condition */ |
| 1670 | checknext(ls, TK_THEN); | 1634 | checknext(ls, TK_THEN); |
| 1671 | line = ls->linenumber; | 1635 | if (ls->t.token == TK_BREAK) { /* 'if x then break' ? */ |
| 1672 | if (issinglejump(ls, &jlb, &target)) { /* 'if x then goto' ? */ | 1636 | int line = ls->linenumber; |
| 1673 | luaK_goiffalse(ls->fs, &v); /* will jump to label if condition is true */ | 1637 | luaK_goiffalse(ls->fs, &v); /* will jump if condition is true */ |
| 1638 | luaX_next(ls); /* skip 'break' */ | ||
| 1674 | enterblock(fs, &bl, 0); /* must enter block before 'goto' */ | 1639 | enterblock(fs, &bl, 0); /* must enter block before 'goto' */ |
| 1675 | if (jlb != NULL) /* forward jump? */ | 1640 | newgotoentry(ls, luaS_newliteral(ls->L, "break"), line, v.t); |
| 1676 | newgotoentry(ls, jlb, line, v.t); /* will be resolved later */ | ||
| 1677 | else /* backward jump */ | ||
| 1678 | luaK_patchlist(fs, v.t, target); /* jump directly to 'target' */ | ||
| 1679 | while (testnext(ls, ';')) {} /* skip semicolons */ | 1641 | while (testnext(ls, ';')) {} /* skip semicolons */ |
| 1680 | if (block_follow(ls, 0)) { /* jump is the entire block? */ | 1642 | if (block_follow(ls, 0)) { /* jump is the entire block? */ |
| 1681 | leaveblock(fs); | 1643 | leaveblock(fs); |
| @@ -1684,7 +1646,7 @@ static void test_then_block (LexState *ls, int *escapelist) { | |||
| 1684 | else /* must skip over 'then' part if condition is false */ | 1646 | else /* must skip over 'then' part if condition is false */ |
| 1685 | jf = luaK_jump(fs); | 1647 | jf = luaK_jump(fs); |
| 1686 | } | 1648 | } |
| 1687 | else { /* regular case (not a jump) */ | 1649 | else { /* regular case (not a break) */ |
| 1688 | luaK_goiftrue(ls->fs, &v); /* skip over block if condition is false */ | 1650 | luaK_goiftrue(ls->fs, &v); /* skip over block if condition is false */ |
| 1689 | enterblock(fs, &bl, 0); | 1651 | enterblock(fs, &bl, 0); |
| 1690 | jf = v.f; | 1652 | jf = v.f; |
diff --git a/testes/code.lua b/testes/code.lua index 34b04668..1f971cd7 100644 --- a/testes/code.lua +++ b/testes/code.lua | |||
| @@ -392,28 +392,6 @@ check(function (a, b) | |||
| 392 | end, | 392 | end, |
| 393 | 'TEST', 'JMP', 'TEST', 'JMP', 'ADDI', 'MMBINI', 'JMP', 'RETURN0') | 393 | 'TEST', 'JMP', 'TEST', 'JMP', 'ADDI', 'MMBINI', 'JMP', 'RETURN0') |
| 394 | 394 | ||
| 395 | checkequal( | ||
| 396 | function (a) while a < 10 do a = a + 1 end end, | ||
| 397 | function (a) | ||
| 398 | ::loop:: | ||
| 399 | if not (a < 10) then goto exit end | ||
| 400 | a = a + 1 | ||
| 401 | goto loop | ||
| 402 | ::exit:: | ||
| 403 | end | ||
| 404 | ) | ||
| 405 | |||
| 406 | checkequal( | ||
| 407 | function (a) repeat local x = a + 1; a = x until a > 0 end, | ||
| 408 | function (a) | ||
| 409 | ::loop:: do | ||
| 410 | local x = a + 1 | ||
| 411 | a = x | ||
| 412 | end | ||
| 413 | if not (a > 0) then goto loop end | ||
| 414 | end | ||
| 415 | ) | ||
| 416 | |||
| 417 | checkequal(function () return 6 or true or nil end, | 395 | checkequal(function () return 6 or true or nil end, |
| 418 | function () return k6 or kTrue or kNil end) | 396 | function () return k6 or kTrue or kNil end) |
| 419 | 397 | ||
