commit 81f2401c6dc6afc819787a0b651f9e4be241e942
parent 508a705c1c08d883473199d6ba019d186c28b9df
Author: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date: Wed, 4 Dec 2019 16:51:26 -0300
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:
M | lvm.c | | | 191 | ++++++++++++++++++++++++++++++++++++++++++++++++------------------------------- |
1 file changed, 116 insertions(+), 75 deletions(-)
diff --git a/lvm.c b/lvm.c
@@ -80,6 +80,21 @@
#endif
+/*
+** Try to convert a value from string to a number value.
+** If the value is not a string or is a string not representing
+** a valid numeral (or if coercions from strings to numbers
+** are disabled via macro 'cvt2num'), do not modify 'result'
+** and return 0.
+*/
+static int l_strton (const TValue *obj, TValue *result) {
+ lua_assert(obj != result);
+ if (!cvt2num(obj)) /* is object not a string? */
+ return 0;
+ else
+ return (luaO_str2num(svalue(obj), result) == vslen(obj) + 1);
+}
+
/*
** 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) {
*n = cast_num(ivalue(obj));
return 1;
}
- else if (cvt2num(obj) && /* string coercible to number? */
- luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) {
+ else if (l_strton(obj, &v)) { /* string coercible to number? */
*n = nvalue(&v); /* convert result of 'luaO_str2num' to a float */
return 1;
}
@@ -111,7 +125,7 @@ int luaV_flttointeger (lua_Number n, lua_Integer *p, int mode) {
lua_Number f = l_floor(n);
if (n != f) { /* not an integral value? */
if (mode == 0) return 0; /* fails if mode demands integral value */
- else if (mode > 1) /* needs ceil? */
+ else if (mode == 2) /* needs ceil? */
f += 1; /* convert floor to ceil (remember: n != f) */
}
return lua_numbertointeger(f, p);
@@ -140,27 +154,27 @@ int luaV_tointegerns (const TValue *obj, lua_Integer *p, int mode) {
*/
int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode) {
TValue v;
- if (cvt2num(obj) && luaO_str2num(svalue(obj), &v) == vslen(obj) + 1)
- obj = &v; /* change string to its corresponding number */
+ if (l_strton(obj, &v)) /* does 'obj' point to a numerical string? */
+ obj = &v; /* change it to point to its corresponding number */
return luaV_tointegerns(obj, p, mode);
}
/*
** Try to convert a 'for' limit to an integer, preserving the semantics
-** of the loop. (The following explanation assumes a positive step;
-** it is valid for negative steps mutatis mutandis.)
-** Return true if the loop must not run.
+** of the loop. Return true if the loop must not run; otherwise, '*p'
+** gets the integer limit.
+** (The following explanation assumes a positive step; it is valid for
+** negative steps mutatis mutandis.)
** If the limit is an integer or can be converted to an integer,
** rounding down, that is the limit.
** Otherwise, check whether the limit can be converted to a float. If
** the float is too large, clip it to LUA_MAXINTEGER. If the float
** is too negative, the loop should not run, because any initial
-** integer value is greater than such limit; so, it returns true to
-** signal that.
-** (For this latter case, no integer limit would be correct; even a
-** limit of LUA_MININTEGER would run the loop once for an initial
-** value equal to LUA_MININTEGER.)
+** integer value is greater than such limit; so, the function returns
+** true to signal that. (For this latter case, no integer limit would be
+** correct; even a limit of LUA_MININTEGER would run the loop once for
+** an initial value equal to LUA_MININTEGER.)
*/
static int forlimit (lua_State *L, lua_Integer init, const TValue *lim,
lua_Integer *p, lua_Integer step) {
@@ -184,6 +198,91 @@ static int forlimit (lua_State *L, lua_Integer init, const TValue *lim,
/*
+** Prepare a numerical for loop (opcode OP_FORPREP).
+** Return true to skip the loop. Otherwise,
+** after preparation, stack will be as follows:
+** ra : internal index (safe copy of the control variable)
+** ra + 1 : loop counter (integer loops) or limit (float loops)
+** ra + 2 : step
+** ra + 3 : control variable
+*/
+static int forprep (lua_State *L, StkId ra) {
+ TValue *pinit = s2v(ra);
+ TValue *plimit = s2v(ra + 1);
+ TValue *pstep = s2v(ra + 2);
+ if (ttisinteger(pinit) && ttisinteger(pstep)) { /* integer loop? */
+ lua_Integer init = ivalue(pinit);
+ lua_Integer step = ivalue(pstep);
+ lua_Integer limit;
+ if (step == 0)
+ luaG_runerror(L, "'for' step is zero");
+ setivalue(s2v(ra + 3), init); /* control variable */
+ if (forlimit(L, init, plimit, &limit, step))
+ return 1; /* skip the loop */
+ else { /* prepare loop counter */
+ lua_Unsigned count;
+ if (step > 0) { /* ascending loop? */
+ count = l_castS2U(limit) - l_castS2U(init);
+ if (step != 1) /* avoid division in the too common case */
+ count /= l_castS2U(step);
+ }
+ else { /* step < 0; descending loop */
+ count = l_castS2U(init) - l_castS2U(limit);
+ /* 'step+1' avoids negating 'mininteger' */
+ count /= l_castS2U(-(step + 1)) + 1u;
+ }
+ /* store the counter in place of the limit (which won't be
+ needed anymore */
+ setivalue(plimit, l_castU2S(count));
+ }
+ }
+ else { /* try making all values floats */
+ lua_Number init; lua_Number limit; lua_Number step;
+ if (unlikely(!tonumber(plimit, &limit)))
+ luaG_forerror(L, plimit, "limit");
+ if (unlikely(!tonumber(pstep, &step)))
+ luaG_forerror(L, pstep, "step");
+ if (unlikely(!tonumber(pinit, &init)))
+ luaG_forerror(L, pinit, "initial value");
+ if (step == 0)
+ luaG_runerror(L, "'for' step is zero");
+ if (luai_numlt(0, step) ? luai_numlt(limit, init)
+ : luai_numlt(init, limit))
+ return 1; /* skip the loop */
+ else {
+ /* make sure internal values are all floats */
+ setfltvalue(plimit, limit);
+ setfltvalue(pstep, step);
+ setfltvalue(s2v(ra), init); /* internal index */
+ setfltvalue(s2v(ra + 3), init); /* control variable */
+ }
+ }
+ return 0;
+}
+
+
+/*
+** Execute a step of a float numerical for loop, returning
+** true iff the loop must continue. (The integer case is
+** written online with opcode OP_FORLOOP, for performance.)
+*/
+static int floatforloop (StkId ra) {
+ lua_Number step = fltvalue(s2v(ra + 2));
+ lua_Number limit = fltvalue(s2v(ra + 1));
+ lua_Number idx = fltvalue(s2v(ra)); /* internal index */
+ idx = luai_numadd(L, idx, step); /* increment index */
+ if (luai_numlt(0, step) ? luai_numle(idx, limit)
+ : luai_numle(limit, idx)) {
+ chgfltvalue(s2v(ra), idx); /* update internal index */
+ setfltvalue(s2v(ra + 3), idx); /* and control variable */
+ return 1; /* jump back */
+ }
+ else
+ return 0; /* finish the loop */
+}
+
+
+/*
** Finish the table access 'val = t[key]'.
** if 'slot' is NULL, 't' is not a table; otherwise, 'slot' points to
** t[k] entry (which must be empty).
@@ -1631,73 +1730,15 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
pc -= GETARG_Bx(i); /* jump back */
}
}
- else { /* floating loop */
- lua_Number step = fltvalue(s2v(ra + 2));
- lua_Number limit = fltvalue(s2v(ra + 1));
- lua_Number idx = fltvalue(s2v(ra));
- idx = luai_numadd(L, idx, step); /* increment index */
- if (luai_numlt(0, step) ? luai_numle(idx, limit)
- : luai_numle(limit, idx)) {
- chgfltvalue(s2v(ra), idx); /* update internal index */
- setfltvalue(s2v(ra + 3), idx); /* and control variable */
- pc -= GETARG_Bx(i); /* jump back */
- }
- }
+ else if (floatforloop(ra)) /* float loop */
+ pc -= GETARG_Bx(i); /* jump back */
updatetrap(ci); /* allows a signal to break the loop */
vmbreak;
}
vmcase(OP_FORPREP) {
- TValue *pinit = s2v(ra);
- TValue *plimit = s2v(ra + 1);
- TValue *pstep = s2v(ra + 2);
savestate(L, ci); /* in case of errors */
- if (ttisinteger(pinit) && ttisinteger(pstep)) { /* integer loop? */
- lua_Integer init = ivalue(pinit);
- lua_Integer step = ivalue(pstep);
- lua_Integer limit;
- if (step == 0)
- luaG_runerror(L, "'for' step is zero");
- setivalue(s2v(ra + 3), init); /* control variable */
- if (forlimit(L, init, plimit, &limit, step))
- pc += GETARG_Bx(i) + 1; /* skip the loop */
- else { /* prepare loop counter */
- lua_Unsigned count;
- if (step > 0) { /* ascending loop? */
- count = l_castS2U(limit) - l_castS2U(init);
- if (step != 1) /* avoid division in the too common case */
- count /= l_castS2U(step);
- }
- else { /* step < 0; descending loop */
- count = l_castS2U(init) - l_castS2U(limit);
- /* 'step+1' avoids negating 'mininteger' */
- count /= l_castS2U(-(step + 1)) + 1u;
- }
- /* store the counter in place of the limit (which won't be
- needed anymore */
- setivalue(plimit, l_castU2S(count));
- }
- }
- else { /* try making all values floats */
- lua_Number init; lua_Number limit; lua_Number step;
- if (unlikely(!tonumber(plimit, &limit)))
- luaG_forerror(L, plimit, "limit");
- if (unlikely(!tonumber(pstep, &step)))
- luaG_forerror(L, pstep, "step");
- if (unlikely(!tonumber(pinit, &init)))
- luaG_forerror(L, pinit, "initial value");
- if (step == 0)
- luaG_runerror(L, "'for' step is zero");
- if (luai_numlt(0, step) ? luai_numlt(limit, init)
- : luai_numlt(init, limit))
- pc += GETARG_Bx(i) + 1; /* skip the loop */
- else {
- /* make sure internal values are all float */
- setfltvalue(plimit, limit);
- setfltvalue(pstep, step);
- setfltvalue(s2v(ra), init); /* internal index */
- setfltvalue(s2v(ra + 3), init); /* control variable */
- }
- }
+ if (forprep(L, ra))
+ pc += GETARG_Bx(i) + 1; /* skip the loop */
vmbreak;
}
vmcase(OP_TFORPREP) {