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.
Diffstat (limited to '')
| -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) { |
