diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-12-04 16:51:53 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-12-04 16:51:53 -0300 |
commit | 81f2401c6dc6afc819787a0b651f9e4be241e942 (patch) | |
tree | 0d7a253bee771ad300702c45e332409d398d521a | |
parent | 508a705c1c08d883473199d6ba019d186c28b9df (diff) | |
download | lua-81f2401c6dc6afc819787a0b651f9e4be241e942.tar.gz lua-81f2401c6dc6afc819787a0b651f9e4be241e942.tar.bz2 lua-81f2401c6dc6afc819787a0b651f9e4be241e942.zip |
Code reorganization for opcodes OP_FORPREP and OP_FORLOOP
Parts of the code for opcodes OP_FORPREP and OP_FORLOOP were moved
to functions outside the interpreter loop.
-rw-r--r-- | lvm.c | 191 |
1 files changed, 116 insertions, 75 deletions
@@ -80,6 +80,21 @@ | |||
80 | #endif | 80 | #endif |
81 | 81 | ||
82 | 82 | ||
83 | /* | ||
84 | ** Try to convert a value from string to a number value. | ||
85 | ** If the value is not a string or is a string not representing | ||
86 | ** a valid numeral (or if coercions from strings to numbers | ||
87 | ** are disabled via macro 'cvt2num'), do not modify 'result' | ||
88 | ** and return 0. | ||
89 | */ | ||
90 | static int l_strton (const TValue *obj, TValue *result) { | ||
91 | lua_assert(obj != result); | ||
92 | if (!cvt2num(obj)) /* is object not a string? */ | ||
93 | return 0; | ||
94 | else | ||
95 | return (luaO_str2num(svalue(obj), result) == vslen(obj) + 1); | ||
96 | } | ||
97 | |||
83 | 98 | ||
84 | /* | 99 | /* |
85 | ** Try to convert a value to a float. The float case is already handled | 100 | ** Try to convert a value to a float. The float case is already handled |
@@ -91,8 +106,7 @@ int luaV_tonumber_ (const TValue *obj, lua_Number *n) { | |||
91 | *n = cast_num(ivalue(obj)); | 106 | *n = cast_num(ivalue(obj)); |
92 | return 1; | 107 | return 1; |
93 | } | 108 | } |
94 | else if (cvt2num(obj) && /* string coercible to number? */ | 109 | else if (l_strton(obj, &v)) { /* string coercible to number? */ |
95 | luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) { | ||
96 | *n = nvalue(&v); /* convert result of 'luaO_str2num' to a float */ | 110 | *n = nvalue(&v); /* convert result of 'luaO_str2num' to a float */ |
97 | return 1; | 111 | return 1; |
98 | } | 112 | } |
@@ -111,7 +125,7 @@ int luaV_flttointeger (lua_Number n, lua_Integer *p, int mode) { | |||
111 | lua_Number f = l_floor(n); | 125 | lua_Number f = l_floor(n); |
112 | if (n != f) { /* not an integral value? */ | 126 | if (n != f) { /* not an integral value? */ |
113 | if (mode == 0) return 0; /* fails if mode demands integral value */ | 127 | if (mode == 0) return 0; /* fails if mode demands integral value */ |
114 | else if (mode > 1) /* needs ceil? */ | 128 | else if (mode == 2) /* needs ceil? */ |
115 | f += 1; /* convert floor to ceil (remember: n != f) */ | 129 | f += 1; /* convert floor to ceil (remember: n != f) */ |
116 | } | 130 | } |
117 | return lua_numbertointeger(f, p); | 131 | return lua_numbertointeger(f, p); |
@@ -140,27 +154,27 @@ int luaV_tointegerns (const TValue *obj, lua_Integer *p, int mode) { | |||
140 | */ | 154 | */ |
141 | int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode) { | 155 | int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode) { |
142 | TValue v; | 156 | TValue v; |
143 | if (cvt2num(obj) && luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) | 157 | if (l_strton(obj, &v)) /* does 'obj' point to a numerical string? */ |
144 | obj = &v; /* change string to its corresponding number */ | 158 | obj = &v; /* change it to point to its corresponding number */ |
145 | return luaV_tointegerns(obj, p, mode); | 159 | return luaV_tointegerns(obj, p, mode); |
146 | } | 160 | } |
147 | 161 | ||
148 | 162 | ||
149 | /* | 163 | /* |
150 | ** Try to convert a 'for' limit to an integer, preserving the semantics | 164 | ** Try to convert a 'for' limit to an integer, preserving the semantics |
151 | ** of the loop. (The following explanation assumes a positive step; | 165 | ** of the loop. Return true if the loop must not run; otherwise, '*p' |
152 | ** it is valid for negative steps mutatis mutandis.) | 166 | ** gets the integer limit. |
153 | ** Return true if the loop must not run. | 167 | ** (The following explanation assumes a positive step; it is valid for |
168 | ** negative steps mutatis mutandis.) | ||
154 | ** If the limit is an integer or can be converted to an integer, | 169 | ** If the limit is an integer or can be converted to an integer, |
155 | ** rounding down, that is the limit. | 170 | ** rounding down, that is the limit. |
156 | ** Otherwise, check whether the limit can be converted to a float. If | 171 | ** Otherwise, check whether the limit can be converted to a float. If |
157 | ** the float is too large, clip it to LUA_MAXINTEGER. If the float | 172 | ** the float is too large, clip it to LUA_MAXINTEGER. If the float |
158 | ** is too negative, the loop should not run, because any initial | 173 | ** is too negative, the loop should not run, because any initial |
159 | ** integer value is greater than such limit; so, it returns true to | 174 | ** integer value is greater than such limit; so, the function returns |
160 | ** signal that. | 175 | ** true to signal that. (For this latter case, no integer limit would be |
161 | ** (For this latter case, no integer limit would be correct; even a | 176 | ** correct; even a limit of LUA_MININTEGER would run the loop once for |
162 | ** limit of LUA_MININTEGER would run the loop once for an initial | 177 | ** an initial value equal to LUA_MININTEGER.) |
163 | ** value equal to LUA_MININTEGER.) | ||
164 | */ | 178 | */ |
165 | static int forlimit (lua_State *L, lua_Integer init, const TValue *lim, | 179 | static int forlimit (lua_State *L, lua_Integer init, const TValue *lim, |
166 | lua_Integer *p, lua_Integer step) { | 180 | lua_Integer *p, lua_Integer step) { |
@@ -184,6 +198,91 @@ static int forlimit (lua_State *L, lua_Integer init, const TValue *lim, | |||
184 | 198 | ||
185 | 199 | ||
186 | /* | 200 | /* |
201 | ** Prepare a numerical for loop (opcode OP_FORPREP). | ||
202 | ** Return true to skip the loop. Otherwise, | ||
203 | ** after preparation, stack will be as follows: | ||
204 | ** ra : internal index (safe copy of the control variable) | ||
205 | ** ra + 1 : loop counter (integer loops) or limit (float loops) | ||
206 | ** ra + 2 : step | ||
207 | ** ra + 3 : control variable | ||
208 | */ | ||
209 | static int forprep (lua_State *L, StkId ra) { | ||
210 | TValue *pinit = s2v(ra); | ||
211 | TValue *plimit = s2v(ra + 1); | ||
212 | TValue *pstep = s2v(ra + 2); | ||
213 | if (ttisinteger(pinit) && ttisinteger(pstep)) { /* integer loop? */ | ||
214 | lua_Integer init = ivalue(pinit); | ||
215 | lua_Integer step = ivalue(pstep); | ||
216 | lua_Integer limit; | ||
217 | if (step == 0) | ||
218 | luaG_runerror(L, "'for' step is zero"); | ||
219 | setivalue(s2v(ra + 3), init); /* control variable */ | ||
220 | if (forlimit(L, init, plimit, &limit, step)) | ||
221 | return 1; /* skip the loop */ | ||
222 | else { /* prepare loop counter */ | ||
223 | lua_Unsigned count; | ||
224 | if (step > 0) { /* ascending loop? */ | ||
225 | count = l_castS2U(limit) - l_castS2U(init); | ||
226 | if (step != 1) /* avoid division in the too common case */ | ||
227 | count /= l_castS2U(step); | ||
228 | } | ||
229 | else { /* step < 0; descending loop */ | ||
230 | count = l_castS2U(init) - l_castS2U(limit); | ||
231 | /* 'step+1' avoids negating 'mininteger' */ | ||
232 | count /= l_castS2U(-(step + 1)) + 1u; | ||
233 | } | ||
234 | /* store the counter in place of the limit (which won't be | ||
235 | needed anymore */ | ||
236 | setivalue(plimit, l_castU2S(count)); | ||
237 | } | ||
238 | } | ||
239 | else { /* try making all values floats */ | ||
240 | lua_Number init; lua_Number limit; lua_Number step; | ||
241 | if (unlikely(!tonumber(plimit, &limit))) | ||
242 | luaG_forerror(L, plimit, "limit"); | ||
243 | if (unlikely(!tonumber(pstep, &step))) | ||
244 | luaG_forerror(L, pstep, "step"); | ||
245 | if (unlikely(!tonumber(pinit, &init))) | ||
246 | luaG_forerror(L, pinit, "initial value"); | ||
247 | if (step == 0) | ||
248 | luaG_runerror(L, "'for' step is zero"); | ||
249 | if (luai_numlt(0, step) ? luai_numlt(limit, init) | ||
250 | : luai_numlt(init, limit)) | ||
251 | return 1; /* skip the loop */ | ||
252 | else { | ||
253 | /* make sure internal values are all floats */ | ||
254 | setfltvalue(plimit, limit); | ||
255 | setfltvalue(pstep, step); | ||
256 | setfltvalue(s2v(ra), init); /* internal index */ | ||
257 | setfltvalue(s2v(ra + 3), init); /* control variable */ | ||
258 | } | ||
259 | } | ||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | |||
264 | /* | ||
265 | ** Execute a step of a float numerical for loop, returning | ||
266 | ** true iff the loop must continue. (The integer case is | ||
267 | ** written online with opcode OP_FORLOOP, for performance.) | ||
268 | */ | ||
269 | static int floatforloop (StkId ra) { | ||
270 | lua_Number step = fltvalue(s2v(ra + 2)); | ||
271 | lua_Number limit = fltvalue(s2v(ra + 1)); | ||
272 | lua_Number idx = fltvalue(s2v(ra)); /* internal index */ | ||
273 | idx = luai_numadd(L, idx, step); /* increment index */ | ||
274 | if (luai_numlt(0, step) ? luai_numle(idx, limit) | ||
275 | : luai_numle(limit, idx)) { | ||
276 | chgfltvalue(s2v(ra), idx); /* update internal index */ | ||
277 | setfltvalue(s2v(ra + 3), idx); /* and control variable */ | ||
278 | return 1; /* jump back */ | ||
279 | } | ||
280 | else | ||
281 | return 0; /* finish the loop */ | ||
282 | } | ||
283 | |||
284 | |||
285 | /* | ||
187 | ** Finish the table access 'val = t[key]'. | 286 | ** Finish the table access 'val = t[key]'. |
188 | ** if 'slot' is NULL, 't' is not a table; otherwise, 'slot' points to | 287 | ** if 'slot' is NULL, 't' is not a table; otherwise, 'slot' points to |
189 | ** t[k] entry (which must be empty). | 288 | ** t[k] entry (which must be empty). |
@@ -1631,73 +1730,15 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1631 | pc -= GETARG_Bx(i); /* jump back */ | 1730 | pc -= GETARG_Bx(i); /* jump back */ |
1632 | } | 1731 | } |
1633 | } | 1732 | } |
1634 | else { /* floating loop */ | 1733 | else if (floatforloop(ra)) /* float loop */ |
1635 | lua_Number step = fltvalue(s2v(ra + 2)); | 1734 | pc -= GETARG_Bx(i); /* jump back */ |
1636 | lua_Number limit = fltvalue(s2v(ra + 1)); | ||
1637 | lua_Number idx = fltvalue(s2v(ra)); | ||
1638 | idx = luai_numadd(L, idx, step); /* increment index */ | ||
1639 | if (luai_numlt(0, step) ? luai_numle(idx, limit) | ||
1640 | : luai_numle(limit, idx)) { | ||
1641 | chgfltvalue(s2v(ra), idx); /* update internal index */ | ||
1642 | setfltvalue(s2v(ra + 3), idx); /* and control variable */ | ||
1643 | pc -= GETARG_Bx(i); /* jump back */ | ||
1644 | } | ||
1645 | } | ||
1646 | updatetrap(ci); /* allows a signal to break the loop */ | 1735 | updatetrap(ci); /* allows a signal to break the loop */ |
1647 | vmbreak; | 1736 | vmbreak; |
1648 | } | 1737 | } |
1649 | vmcase(OP_FORPREP) { | 1738 | vmcase(OP_FORPREP) { |
1650 | TValue *pinit = s2v(ra); | ||
1651 | TValue *plimit = s2v(ra + 1); | ||
1652 | TValue *pstep = s2v(ra + 2); | ||
1653 | savestate(L, ci); /* in case of errors */ | 1739 | savestate(L, ci); /* in case of errors */ |
1654 | if (ttisinteger(pinit) && ttisinteger(pstep)) { /* integer loop? */ | 1740 | if (forprep(L, ra)) |
1655 | lua_Integer init = ivalue(pinit); | 1741 | pc += GETARG_Bx(i) + 1; /* skip the loop */ |
1656 | lua_Integer step = ivalue(pstep); | ||
1657 | lua_Integer limit; | ||
1658 | if (step == 0) | ||
1659 | luaG_runerror(L, "'for' step is zero"); | ||
1660 | setivalue(s2v(ra + 3), init); /* control variable */ | ||
1661 | if (forlimit(L, init, plimit, &limit, step)) | ||
1662 | pc += GETARG_Bx(i) + 1; /* skip the loop */ | ||
1663 | else { /* prepare loop counter */ | ||
1664 | lua_Unsigned count; | ||
1665 | if (step > 0) { /* ascending loop? */ | ||
1666 | count = l_castS2U(limit) - l_castS2U(init); | ||
1667 | if (step != 1) /* avoid division in the too common case */ | ||
1668 | count /= l_castS2U(step); | ||
1669 | } | ||
1670 | else { /* step < 0; descending loop */ | ||
1671 | count = l_castS2U(init) - l_castS2U(limit); | ||
1672 | /* 'step+1' avoids negating 'mininteger' */ | ||
1673 | count /= l_castS2U(-(step + 1)) + 1u; | ||
1674 | } | ||
1675 | /* store the counter in place of the limit (which won't be | ||
1676 | needed anymore */ | ||
1677 | setivalue(plimit, l_castU2S(count)); | ||
1678 | } | ||
1679 | } | ||
1680 | else { /* try making all values floats */ | ||
1681 | lua_Number init; lua_Number limit; lua_Number step; | ||
1682 | if (unlikely(!tonumber(plimit, &limit))) | ||
1683 | luaG_forerror(L, plimit, "limit"); | ||
1684 | if (unlikely(!tonumber(pstep, &step))) | ||
1685 | luaG_forerror(L, pstep, "step"); | ||
1686 | if (unlikely(!tonumber(pinit, &init))) | ||
1687 | luaG_forerror(L, pinit, "initial value"); | ||
1688 | if (step == 0) | ||
1689 | luaG_runerror(L, "'for' step is zero"); | ||
1690 | if (luai_numlt(0, step) ? luai_numlt(limit, init) | ||
1691 | : luai_numlt(init, limit)) | ||
1692 | pc += GETARG_Bx(i) + 1; /* skip the loop */ | ||
1693 | else { | ||
1694 | /* make sure internal values are all float */ | ||
1695 | setfltvalue(plimit, limit); | ||
1696 | setfltvalue(pstep, step); | ||
1697 | setfltvalue(s2v(ra), init); /* internal index */ | ||
1698 | setfltvalue(s2v(ra + 3), init); /* control variable */ | ||
1699 | } | ||
1700 | } | ||
1701 | vmbreak; | 1742 | vmbreak; |
1702 | } | 1743 | } |
1703 | vmcase(OP_TFORPREP) { | 1744 | vmcase(OP_TFORPREP) { |