Browse Source

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.
Roberto Ierusalimschy 5 years ago
parent
commit
81f2401c6d
1 changed files with 116 additions and 75 deletions
  1. 116 75
      lvm.c

+ 116 - 75
lvm.c

@@ -80,6 +80,21 @@
 #endif
 #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
 ** 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));
     *n = cast_num(ivalue(obj));
     return 1;
     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 */
     *n = nvalue(&v);  /* convert result of 'luaO_str2num' to a float */
     return 1;
     return 1;
   }
   }
@@ -111,7 +125,7 @@ int luaV_flttointeger (lua_Number n, lua_Integer *p, int mode) {
   lua_Number f = l_floor(n);
   lua_Number f = l_floor(n);
   if (n != f) {  /* not an integral value? */
   if (n != f) {  /* not an integral value? */
     if (mode == 0) return 0;  /* fails if mode demands 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) */
       f += 1;  /* convert floor to ceil (remember: n != f) */
   }
   }
   return lua_numbertointeger(f, p);
   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) {
 int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode) {
   TValue v;
   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);
   return luaV_tointegerns(obj, p, mode);
 }
 }
 
 
 
 
 /*
 /*
 ** Try to convert a 'for' limit to an integer, preserving the semantics
 ** 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,
 ** If the limit is an integer or can be converted to an integer,
 ** rounding down, that is the limit.
 ** rounding down, that is the limit.
 ** Otherwise, check whether the limit can be converted to a float. If
 ** 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
 ** the float is too large, clip it to LUA_MAXINTEGER.  If the float
 ** is too negative, the loop should not run, because any initial
 ** 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,
 static int forlimit (lua_State *L, lua_Integer init, const TValue *lim,
                                    lua_Integer *p, lua_Integer step) {
                                    lua_Integer *p, lua_Integer step) {
@@ -183,6 +197,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]'.
 ** Finish the table access 'val = t[key]'.
 ** if 'slot' is NULL, 't' is not a table; otherwise, 'slot' points to
 ** if 'slot' is NULL, 't' is not a table; otherwise, 'slot' points to
@@ -1631,73 +1730,15 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
             pc -= GETARG_Bx(i);  /* jump back */
             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 */
         updatetrap(ci);  /* allows a signal to break the loop */
         vmbreak;
         vmbreak;
       }
       }
       vmcase(OP_FORPREP) {
       vmcase(OP_FORPREP) {
-        TValue *pinit = s2v(ra);
-        TValue *plimit = s2v(ra + 1);
-        TValue *pstep = s2v(ra + 2);
         savestate(L, ci);  /* in case of errors */
         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;
         vmbreak;
       }
       }
       vmcase(OP_TFORPREP) {
       vmcase(OP_TFORPREP) {