mirror of
https://github.com/lua/lua
synced 2025-02-07 08:44:01 +03:00
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.
This commit is contained in:
parent
508a705c1c
commit
81f2401c6d
191
lvm.c
191
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) {
|
||||
@ -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]'.
|
||||
** 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 */
|
||||
}
|
||||
}
|
||||
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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user