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 /lvm.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 'lvm.c')
-rw-r--r-- | lvm.c | 147 |
1 files changed, 74 insertions, 73 deletions
@@ -148,35 +148,34 @@ int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode) { | |||
148 | 148 | ||
149 | /* | 149 | /* |
150 | ** Try to convert a 'for' limit to an integer, preserving the semantics | 150 | ** Try to convert a 'for' limit to an integer, preserving the semantics |
151 | ** of the loop. (The following explanation assumes a non-negative step; | 151 | ** of the loop. (The following explanation assumes a positive step; |
152 | ** it is valid for negative steps mutatis mutandis.) | 152 | ** it is valid for negative steps mutatis mutandis.) |
153 | ** If the limit is an integer or can be converted to an integer, | 153 | ** If the limit is an integer or can be converted to an integer, |
154 | ** rounding down, that is it. | 154 | ** rounding down, that is it. |
155 | ** Otherwise, check whether the limit can be converted to a float. If | 155 | ** Otherwise, check whether the limit can be converted to a float. If |
156 | ** the number is too large, it is OK to set the limit as LUA_MAXINTEGER, | 156 | ** the float is too large, clip it to LUA_MAXINTEGER. If the float |
157 | ** which means no limit. If the number is too negative, the loop | 157 | ** is too negative, the loop should not run, because any initial |
158 | ** should not run, because any initial integer value is larger than the | 158 | ** integer value is greater than such limit; so, it sets 'stopnow'. |
159 | ** limit. So, it sets the limit to LUA_MININTEGER. 'stopnow' corrects | 159 | ** (For this latter case, no integer limit would be correct; even a |
160 | ** the extreme case when the initial value is LUA_MININTEGER, in which | 160 | ** limit of LUA_MININTEGER would run the loop once for an initial |
161 | ** case the LUA_MININTEGER limit would still run the loop once. | 161 | ** value equal to LUA_MININTEGER.) |
162 | */ | 162 | */ |
163 | static int forlimit (const TValue *obj, lua_Integer *p, lua_Integer step, | 163 | static int forlimit (const TValue *lim, lua_Integer *p, lua_Integer step, |
164 | int *stopnow) { | 164 | int *stopnow) { |
165 | *stopnow = 0; /* usually, let loops run */ | 165 | *stopnow = 0; /* usually, let loops run */ |
166 | if (ttisinteger(obj)) | 166 | if (!luaV_tointeger(lim, p, (step < 0 ? 2 : 1))) { |
167 | *p = ivalue(obj); | ||
168 | else if (!luaV_tointeger(obj, p, (step < 0 ? 2 : 1))) { | ||
169 | /* not coercible to in integer */ | 167 | /* not coercible to in integer */ |
170 | lua_Number n; /* try to convert to float */ | 168 | lua_Number flim; /* try to convert to float */ |
171 | if (!tonumber(obj, &n)) /* cannot convert to float? */ | 169 | if (!tonumber(lim, &flim)) /* cannot convert to float? */ |
172 | return 0; /* not a number */ | 170 | return 0; /* not a number */ |
173 | if (luai_numlt(0, n)) { /* if true, float is larger than max integer */ | 171 | /* 'flim' is a float out of integer bounds */ |
174 | *p = LUA_MAXINTEGER; | 172 | if (luai_numlt(0, flim)) { /* if it is positive, it is too large */ |
175 | if (step < 0) *stopnow = 1; | 173 | *p = LUA_MAXINTEGER; /* truncate */ |
174 | if (step < 0) *stopnow = 1; /* initial value must be less than it */ | ||
176 | } | 175 | } |
177 | else { /* float is less than min integer */ | 176 | else { /* it is less than min integer */ |
178 | *p = LUA_MININTEGER; | 177 | *p = LUA_MININTEGER; /* truncate */ |
179 | if (step >= 0) *stopnow = 1; | 178 | if (step > 0) *stopnow = 1; /* initial value must be greater than it */ |
180 | } | 179 | } |
181 | } | 180 | } |
182 | return 1; | 181 | return 1; |
@@ -1636,85 +1635,87 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1636 | } | 1635 | } |
1637 | return; | 1636 | return; |
1638 | } | 1637 | } |
1639 | vmcase(OP_FORLOOP1) { | ||
1640 | lua_Integer idx = intop(+, ivalue(s2v(ra)), 1); /* increment index */ | ||
1641 | lua_Integer limit = ivalue(s2v(ra + 1)); | ||
1642 | if (idx <= limit) { | ||
1643 | pc -= GETARG_Bx(i); /* jump back */ | ||
1644 | chgivalue(s2v(ra), idx); /* update internal index... */ | ||
1645 | setivalue(s2v(ra + 3), idx); /* ...and external index */ | ||
1646 | } | ||
1647 | updatetrap(ci); | ||
1648 | vmbreak; | ||
1649 | } | ||
1650 | vmcase(OP_FORPREP1) { | ||
1651 | TValue *init = s2v(ra); | ||
1652 | TValue *plimit = s2v(ra + 1); | ||
1653 | lua_Integer ilimit, initv; | ||
1654 | int stopnow; | ||
1655 | if (unlikely(!forlimit(plimit, &ilimit, 1, &stopnow))) { | ||
1656 | savestate(L, ci); /* for the error message */ | ||
1657 | luaG_forerror(L, plimit, "limit"); | ||
1658 | } | ||
1659 | initv = (stopnow ? 0 : ivalue(init)); | ||
1660 | setivalue(plimit, ilimit); | ||
1661 | setivalue(init, intop(-, initv, 1)); | ||
1662 | pc += GETARG_Bx(i); | ||
1663 | vmbreak; | ||
1664 | } | ||
1665 | vmcase(OP_FORLOOP) { | 1638 | vmcase(OP_FORLOOP) { |
1666 | if (ttisinteger(s2v(ra))) { /* integer loop? */ | 1639 | if (ttisinteger(s2v(ra + 2))) { /* integer loop? */ |
1667 | lua_Integer step = ivalue(s2v(ra + 2)); | 1640 | lua_Unsigned count = l_castS2U(ivalue(s2v(ra))); |
1668 | lua_Integer idx = intop(+, ivalue(s2v(ra)), step); /* new index */ | 1641 | if (count > 0) { /* still more iterations? */ |
1669 | lua_Integer limit = ivalue(s2v(ra + 1)); | 1642 | lua_Integer step = ivalue(s2v(ra + 2)); |
1670 | if ((0 < step) ? (idx <= limit) : (limit <= idx)) { | 1643 | lua_Integer idx = ivalue(s2v(ra + 3)); |
1644 | idx = intop(+, idx, step); /* add step to index */ | ||
1645 | chgivalue(s2v(ra), count - 1); /* update counter... */ | ||
1646 | setivalue(s2v(ra + 3), idx); /* ...and index */ | ||
1671 | pc -= GETARG_Bx(i); /* jump back */ | 1647 | pc -= GETARG_Bx(i); /* jump back */ |
1672 | chgivalue(s2v(ra), idx); /* update internal index... */ | ||
1673 | setivalue(s2v(ra + 3), idx); /* ...and external index */ | ||
1674 | } | 1648 | } |
1675 | } | 1649 | } |
1676 | else { /* floating loop */ | 1650 | else { /* floating loop */ |
1677 | lua_Number step = fltvalue(s2v(ra + 2)); | 1651 | lua_Number step = fltvalue(s2v(ra + 2)); |
1678 | lua_Number limit = fltvalue(s2v(ra + 1)); | 1652 | lua_Number limit = fltvalue(s2v(ra + 1)); |
1679 | lua_Number idx = fltvalue(s2v(ra)); | 1653 | lua_Number idx = fltvalue(s2v(ra + 3)); |
1680 | idx = luai_numadd(L, idx, step); /* inc. index */ | 1654 | idx = luai_numadd(L, idx, step); /* inc. index */ |
1681 | if (luai_numlt(0, step) ? luai_numle(idx, limit) | 1655 | if (luai_numlt(0, step) ? luai_numle(idx, limit) |
1682 | : luai_numle(limit, idx)) { | 1656 | : luai_numle(limit, idx)) { |
1657 | setfltvalue(s2v(ra + 3), idx); /* update index */ | ||
1683 | pc -= GETARG_Bx(i); /* jump back */ | 1658 | pc -= GETARG_Bx(i); /* jump back */ |
1684 | chgfltvalue(s2v(ra), idx); /* update internal index... */ | ||
1685 | setfltvalue(s2v(ra + 3), idx); /* ...and external index */ | ||
1686 | } | 1659 | } |
1687 | } | 1660 | } |
1688 | updatetrap(ci); | 1661 | updatetrap(ci); /* allows a signal to break the loop */ |
1689 | vmbreak; | 1662 | vmbreak; |
1690 | } | 1663 | } |
1691 | vmcase(OP_FORPREP) { | 1664 | vmcase(OP_FORPREP) { |
1692 | TValue *init = s2v(ra); | 1665 | TValue *pinit = s2v(ra); |
1693 | TValue *plimit = s2v(ra + 1); | 1666 | TValue *plimit = s2v(ra + 1); |
1694 | TValue *pstep = s2v(ra + 2); | 1667 | TValue *pstep = s2v(ra + 2); |
1695 | lua_Integer ilimit; | 1668 | lua_Integer ilimit; |
1696 | int stopnow; | 1669 | int stopnow; |
1697 | if (ttisinteger(init) && ttisinteger(pstep) && | 1670 | savestate(L, ci); /* in case of errors */ |
1671 | if (ttisinteger(pinit) && ttisinteger(pstep) && | ||
1698 | forlimit(plimit, &ilimit, ivalue(pstep), &stopnow)) { | 1672 | forlimit(plimit, &ilimit, ivalue(pstep), &stopnow)) { |
1699 | /* all values are integer */ | 1673 | /* integer loop */ |
1700 | lua_Integer initv = (stopnow ? 0 : ivalue(init)); | 1674 | lua_Integer init = ivalue(pinit); |
1701 | setivalue(plimit, ilimit); | 1675 | lua_Integer step = ivalue(pstep); |
1702 | setivalue(init, intop(-, initv, ivalue(pstep))); | 1676 | setivalue(s2v(ra + 3), init); /* control variable */ |
1677 | if (step == 0) | ||
1678 | luaG_runerror(L, "'for' step is zero"); | ||
1679 | else if (stopnow) | ||
1680 | pc += GETARG_Bx(i) + 1; /* skip the loop */ | ||
1681 | else if (step > 0) { /* ascending loop? */ | ||
1682 | if (init > ilimit) | ||
1683 | pc += GETARG_Bx(i) + 1; /* skip the loop */ | ||
1684 | else { | ||
1685 | lua_Unsigned count = l_castS2U(ilimit) - l_castS2U(init); | ||
1686 | if (step != 1) /* avoid division in the too common case */ | ||
1687 | count /= l_castS2U(step); | ||
1688 | setivalue(s2v(ra), count); | ||
1689 | } | ||
1690 | } | ||
1691 | else { /* descending loop */ | ||
1692 | if (init < ilimit) | ||
1693 | pc += GETARG_Bx(i) + 1; /* skip the loop */ | ||
1694 | else { | ||
1695 | lua_Unsigned count = l_castS2U(init) - l_castS2U(ilimit); | ||
1696 | count /= -l_castS2U(step); | ||
1697 | setivalue(s2v(ra), count); | ||
1698 | } | ||
1699 | } | ||
1703 | } | 1700 | } |
1704 | else { /* try making all values floats */ | 1701 | else { /* try making all values floats */ |
1705 | lua_Number ninit; lua_Number nlimit; lua_Number nstep; | 1702 | lua_Number init; lua_Number flimit; lua_Number step; |
1706 | savestate(L, ci); /* in case of errors */ | 1703 | if (unlikely(!tonumber(plimit, &flimit))) |
1707 | if (unlikely(!tonumber(plimit, &nlimit))) | ||
1708 | luaG_forerror(L, plimit, "limit"); | 1704 | luaG_forerror(L, plimit, "limit"); |
1709 | setfltvalue(plimit, nlimit); | 1705 | setfltvalue(plimit, flimit); |
1710 | if (unlikely(!tonumber(pstep, &nstep))) | 1706 | if (unlikely(!tonumber(pstep, &step))) |
1711 | luaG_forerror(L, pstep, "step"); | 1707 | luaG_forerror(L, pstep, "step"); |
1712 | setfltvalue(pstep, nstep); | 1708 | setfltvalue(pstep, step); |
1713 | if (unlikely(!tonumber(init, &ninit))) | 1709 | if (unlikely(!tonumber(pinit, &init))) |
1714 | luaG_forerror(L, init, "initial value"); | 1710 | luaG_forerror(L, pinit, "initial value"); |
1715 | setfltvalue(init, luai_numsub(L, ninit, nstep)); | 1711 | if (step == 0) |
1712 | luaG_runerror(L, "'for' step is zero"); | ||
1713 | if (luai_numlt(0, step) ? luai_numlt(flimit, init) | ||
1714 | : luai_numlt(init, flimit)) | ||
1715 | pc += GETARG_Bx(i) + 1; /* skip the loop */ | ||
1716 | else | ||
1717 | setfltvalue(s2v(ra + 3), init); /* control variable */ | ||
1716 | } | 1718 | } |
1717 | pc += GETARG_Bx(i); | ||
1718 | vmbreak; | 1719 | vmbreak; |
1719 | } | 1720 | } |
1720 | vmcase(OP_TFORPREP) { | 1721 | vmcase(OP_TFORPREP) { |