aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2019-03-21 16:01:55 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2019-03-21 16:01:55 -0300
commit682054920ddc434fd4a7f8cc78027dbb03f47f00 (patch)
treec1f57903f57c9e13a338b09f2c625020aac31e7b
parentf53eabeed855081fa38e9af5cf7c977915f5213f (diff)
downloadlua-682054920ddc434fd4a7f8cc78027dbb03f47f00.tar.gz
lua-682054920ddc434fd4a7f8cc78027dbb03f47f00.tar.bz2
lua-682054920ddc434fd4a7f8cc78027dbb03f47f00.zip
Details in the implementation of the integer 'for' loop
Changed some implementation details; in particular, it is back using an internal variable to keep the index, with the control variable being only a copy of that internal variable. (The direct use of the control variable demands a check of its type for each access, which offsets the gains from the use of a single variable.)
-rw-r--r--lvm.c87
-rw-r--r--testes/nextvar.lua6
2 files changed, 49 insertions, 44 deletions
diff --git a/lvm.c b/lvm.c
index 75b05f00..31b4dc36 100644
--- a/lvm.c
+++ b/lvm.c
@@ -150,35 +150,36 @@ int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode) {
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 positive 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** Return true if the loop must not run.
153** If the limit is an integer or can be converted to an integer, 154** If the limit is an integer or can be converted to an integer,
154** rounding down, that is it. 155** rounding down, that is the limit.
155** Otherwise, check whether the limit can be converted to a float. If 156** Otherwise, check whether the limit can be converted to a float. If
156** the float is too large, clip it to LUA_MAXINTEGER. If the float 157** the float is too large, clip it to LUA_MAXINTEGER. If the float
157** is too negative, the loop should not run, because any initial 158** is too negative, the loop should not run, because any initial
158** integer value is greater than such limit; so, it sets 'stopnow'. 159** integer value is greater than such limit; so, it returns true to
160** signal that.
159** (For this latter case, no integer limit would be correct; even a 161** (For this latter case, no integer limit would be correct; even a
160** limit of LUA_MININTEGER would run the loop once for an initial 162** limit of LUA_MININTEGER would run the loop once for an initial
161** value equal to LUA_MININTEGER.) 163** value equal to LUA_MININTEGER.)
162*/ 164*/
163static int forlimit (const TValue *lim, lua_Integer *p, lua_Integer step, 165static int forlimit (lua_State *L, lua_Integer init, const TValue *lim,
164 int *stopnow) { 166 lua_Integer *p, lua_Integer step) {
165 *stopnow = 0; /* usually, let loops run */
166 if (!luaV_tointeger(lim, p, (step < 0 ? 2 : 1))) { 167 if (!luaV_tointeger(lim, p, (step < 0 ? 2 : 1))) {
167 /* not coercible to in integer */ 168 /* not coercible to in integer */
168 lua_Number flim; /* try to convert to float */ 169 lua_Number flim; /* try to convert to float */
169 if (!tonumber(lim, &flim)) /* cannot convert to float? */ 170 if (!tonumber(lim, &flim)) /* cannot convert to float? */
170 return 0; /* not a number */ 171 luaG_forerror(L, lim, "limit");
171 /* 'flim' is a float out of integer bounds */ 172 /* else 'flim' is a float out of integer bounds */
172 if (luai_numlt(0, flim)) { /* if it is positive, it is too large */ 173 if (luai_numlt(0, flim)) { /* if it is positive, it is too large */
174 if (step < 0) return 1; /* initial value must be less than it */
173 *p = LUA_MAXINTEGER; /* truncate */ 175 *p = LUA_MAXINTEGER; /* truncate */
174 if (step < 0) *stopnow = 1; /* initial value must be less than it */
175 } 176 }
176 else { /* it is less than min integer */ 177 else { /* it is less than min integer */
178 if (step > 0) return 1; /* initial value must be greater than it */
177 *p = LUA_MININTEGER; /* truncate */ 179 *p = LUA_MININTEGER; /* truncate */
178 if (step > 0) *stopnow = 1; /* initial value must be greater than it */
179 } 180 }
180 } 181 }
181 return 1; 182 return (step > 0 ? init > *p : init < *p); /* not to run? */
182} 183}
183 184
184 185
@@ -1637,24 +1638,26 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
1637 } 1638 }
1638 vmcase(OP_FORLOOP) { 1639 vmcase(OP_FORLOOP) {
1639 if (ttisinteger(s2v(ra + 2))) { /* integer loop? */ 1640 if (ttisinteger(s2v(ra + 2))) { /* integer loop? */
1640 lua_Unsigned count = l_castS2U(ivalue(s2v(ra))); 1641 lua_Unsigned count = l_castS2U(ivalue(s2v(ra + 1)));
1641 if (count > 0) { /* still more iterations? */ 1642 if (count > 0) { /* still more iterations? */
1642 lua_Integer step = ivalue(s2v(ra + 2)); 1643 lua_Integer step = ivalue(s2v(ra + 2));
1643 lua_Integer idx = ivalue(s2v(ra + 3)); 1644 lua_Integer idx = ivalue(s2v(ra)); /* internal index */
1645 chgivalue(s2v(ra + 1), count - 1); /* update counter */
1644 idx = intop(+, idx, step); /* add step to index */ 1646 idx = intop(+, idx, step); /* add step to index */
1645 chgivalue(s2v(ra), count - 1); /* update counter... */ 1647 chgivalue(s2v(ra), idx); /* update internal index */
1646 setivalue(s2v(ra + 3), idx); /* ...and index */ 1648 setivalue(s2v(ra + 3), idx); /* and control variable */
1647 pc -= GETARG_Bx(i); /* jump back */ 1649 pc -= GETARG_Bx(i); /* jump back */
1648 } 1650 }
1649 } 1651 }
1650 else { /* floating loop */ 1652 else { /* floating loop */
1651 lua_Number step = fltvalue(s2v(ra + 2)); 1653 lua_Number step = fltvalue(s2v(ra + 2));
1652 lua_Number limit = fltvalue(s2v(ra + 1)); 1654 lua_Number limit = fltvalue(s2v(ra + 1));
1653 lua_Number idx = fltvalue(s2v(ra + 3)); 1655 lua_Number idx = fltvalue(s2v(ra));
1654 idx = luai_numadd(L, idx, step); /* inc. index */ 1656 idx = luai_numadd(L, idx, step); /* increment index */
1655 if (luai_numlt(0, step) ? luai_numle(idx, limit) 1657 if (luai_numlt(0, step) ? luai_numle(idx, limit)
1656 : luai_numle(limit, idx)) { 1658 : luai_numle(limit, idx)) {
1657 setfltvalue(s2v(ra + 3), idx); /* update index */ 1659 chgfltvalue(s2v(ra), idx); /* update internal index */
1660 setfltvalue(s2v(ra + 3), idx); /* and control variable */
1658 pc -= GETARG_Bx(i); /* jump back */ 1661 pc -= GETARG_Bx(i); /* jump back */
1659 } 1662 }
1660 } 1663 }
@@ -1665,56 +1668,52 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
1665 TValue *pinit = s2v(ra); 1668 TValue *pinit = s2v(ra);
1666 TValue *plimit = s2v(ra + 1); 1669 TValue *plimit = s2v(ra + 1);
1667 TValue *pstep = s2v(ra + 2); 1670 TValue *pstep = s2v(ra + 2);
1668 lua_Integer ilimit;
1669 int stopnow;
1670 savestate(L, ci); /* in case of errors */ 1671 savestate(L, ci); /* in case of errors */
1671 if (ttisinteger(pinit) && ttisinteger(pstep) && 1672 if (ttisinteger(pinit) && ttisinteger(pstep)) { /* integer loop? */
1672 forlimit(plimit, &ilimit, ivalue(pstep), &stopnow)) {
1673 /* integer loop */
1674 lua_Integer init = ivalue(pinit); 1673 lua_Integer init = ivalue(pinit);
1675 lua_Integer step = ivalue(pstep); 1674 lua_Integer step = ivalue(pstep);
1676 setivalue(s2v(ra + 3), init); /* control variable */ 1675 lua_Integer limit;
1677 if (step == 0) 1676 if (step == 0)
1678 luaG_runerror(L, "'for' step is zero"); 1677 luaG_runerror(L, "'for' step is zero");
1679 else if (stopnow) 1678 setivalue(s2v(ra + 3), init); /* control variable */
1679 if (forlimit(L, init, plimit, &limit, step))
1680 pc += GETARG_Bx(i) + 1; /* skip the loop */ 1680 pc += GETARG_Bx(i) + 1; /* skip the loop */
1681 else if (step > 0) { /* ascending loop? */ 1681 else { /* prepare loop counter */
1682 if (init > ilimit) 1682 lua_Unsigned count;
1683 pc += GETARG_Bx(i) + 1; /* skip the loop */ 1683 if (step > 0) { /* ascending loop? */
1684 else { 1684 count = l_castS2U(limit) - l_castS2U(init);
1685 lua_Unsigned count = l_castS2U(ilimit) - l_castS2U(init);
1686 if (step != 1) /* avoid division in the too common case */ 1685 if (step != 1) /* avoid division in the too common case */
1687 count /= l_castS2U(step); 1686 count /= l_castS2U(step);
1688 setivalue(s2v(ra), count);
1689 } 1687 }
1690 } 1688 else { /* step < 0; descending loop */
1691 else { /* descending loop */ 1689 count = l_castS2U(init) - l_castS2U(limit);
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); 1690 count /= -l_castS2U(step);
1697 setivalue(s2v(ra), count);
1698 } 1691 }
1692 /* store the counter in place of the limit (which won't be
1693 needed anymore */
1694 setivalue(plimit, l_castU2S(count));
1699 } 1695 }
1700 } 1696 }
1701 else { /* try making all values floats */ 1697 else { /* try making all values floats */
1702 lua_Number init; lua_Number flimit; lua_Number step; 1698 lua_Number init; lua_Number limit; lua_Number step;
1703 if (unlikely(!tonumber(plimit, &flimit))) 1699 if (unlikely(!tonumber(plimit, &limit)))
1704 luaG_forerror(L, plimit, "limit"); 1700 luaG_forerror(L, plimit, "limit");
1705 setfltvalue(plimit, flimit);
1706 if (unlikely(!tonumber(pstep, &step))) 1701 if (unlikely(!tonumber(pstep, &step)))
1707 luaG_forerror(L, pstep, "step"); 1702 luaG_forerror(L, pstep, "step");
1708 setfltvalue(pstep, step);
1709 if (unlikely(!tonumber(pinit, &init))) 1703 if (unlikely(!tonumber(pinit, &init)))
1710 luaG_forerror(L, pinit, "initial value"); 1704 luaG_forerror(L, pinit, "initial value");
1711 if (step == 0) 1705 if (step == 0)
1712 luaG_runerror(L, "'for' step is zero"); 1706 luaG_runerror(L, "'for' step is zero");
1713 if (luai_numlt(0, step) ? luai_numlt(flimit, init) 1707 if (luai_numlt(0, step) ? luai_numlt(limit, init)
1714 : luai_numlt(init, flimit)) 1708 : luai_numlt(init, limit))
1715 pc += GETARG_Bx(i) + 1; /* skip the loop */ 1709 pc += GETARG_Bx(i) + 1; /* skip the loop */
1716 else 1710 else {
1711 /* make sure internal values are all float */
1712 setfltvalue(plimit, limit);
1713 setfltvalue(pstep, step);
1714 setfltvalue(s2v(ra), init); /* internal index */
1717 setfltvalue(s2v(ra + 3), init); /* control variable */ 1715 setfltvalue(s2v(ra + 3), init); /* control variable */
1716 }
1718 } 1717 }
1719 vmbreak; 1718 vmbreak;
1720 } 1719 }
diff --git a/testes/nextvar.lua b/testes/nextvar.lua
index e769ccdd..87a6bfa8 100644
--- a/testes/nextvar.lua
+++ b/testes/nextvar.lua
@@ -544,6 +544,12 @@ do
544 a = 0; for i=1.0, 0.99999, -1 do a=a+1 end; assert(a==1) 544 a = 0; for i=1.0, 0.99999, -1 do a=a+1 end; assert(a==1)
545end 545end
546 546
547do -- changing the control variable
548 local a
549 a = 0; for i = 1, 10 do a = a + 1; i = "x" end; assert(a == 10)
550 a = 0; for i = 10.0, 1, -1 do a = a + 1; i = "x" end; assert(a == 10)
551end
552
547-- conversion 553-- conversion
548a = 0; for i="10","1","-2" do a=a+1 end; assert(a==5) 554a = 0; for i="10","1","-2" do a=a+1 end; assert(a==5)
549 555