aboutsummaryrefslogtreecommitdiff
path: root/lvm.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2019-03-19 10:53:18 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2019-03-19 10:53:18 -0300
commit9b37a4695ebf50b37b5b4fb279ae948f23b5b6a0 (patch)
tree2a6b0f6c1c2eb962bb383175eb0a67ea81a4564d /lvm.c
parent1e0c73d5b643707335b06abd2546a83d9439d14c (diff)
downloadlua-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.c147
1 files changed, 74 insertions, 73 deletions
diff --git a/lvm.c b/lvm.c
index 23e7ff70..75b05f00 100644
--- a/lvm.c
+++ b/lvm.c
@@ -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*/
163static int forlimit (const TValue *obj, lua_Integer *p, lua_Integer step, 163static 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) {