diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-03-21 16:01:55 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-03-21 16:01:55 -0300 |
commit | 682054920ddc434fd4a7f8cc78027dbb03f47f00 (patch) | |
tree | c1f57903f57c9e13a338b09f2c625020aac31e7b | |
parent | f53eabeed855081fa38e9af5cf7c977915f5213f (diff) | |
download | lua-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.c | 87 | ||||
-rw-r--r-- | testes/nextvar.lua | 6 |
2 files changed, 49 insertions, 44 deletions
@@ -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 | */ |
163 | static int forlimit (const TValue *lim, lua_Integer *p, lua_Integer step, | 165 | static 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) |
545 | end | 545 | end |
546 | 546 | ||
547 | do -- 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) | ||
551 | end | ||
552 | |||
547 | -- conversion | 553 | -- conversion |
548 | a = 0; for i="10","1","-2" do a=a+1 end; assert(a==5) | 554 | a = 0; for i="10","1","-2" do a=a+1 end; assert(a==5) |
549 | 555 | ||