mirror of
https://github.com/lua/lua
synced 2024-11-21 20:31:22 +03:00
Using CIST_CLSRET instead of trick with 'nresults'
The callstatus flag CIST_CLSRET is used in all tests for the presence of variables to be closed in C functions.
This commit is contained in:
parent
a546138d15
commit
f407b3c4a1
8
lapi.c
8
lapi.c
@ -207,7 +207,7 @@ LUA_API void lua_settop (lua_State *L, int idx) {
|
|||||||
}
|
}
|
||||||
newtop = L->top.p + diff;
|
newtop = L->top.p + diff;
|
||||||
if (diff < 0 && L->tbclist.p >= newtop) {
|
if (diff < 0 && L->tbclist.p >= newtop) {
|
||||||
lua_assert(hastocloseCfunc(ci->nresults));
|
lua_assert(ci->callstatus & CIST_CLSRET);
|
||||||
newtop = luaF_close(L, newtop, CLOSEKTOP, 0);
|
newtop = luaF_close(L, newtop, CLOSEKTOP, 0);
|
||||||
}
|
}
|
||||||
L->top.p = newtop; /* correct top only after closing any upvalue */
|
L->top.p = newtop; /* correct top only after closing any upvalue */
|
||||||
@ -219,7 +219,7 @@ LUA_API void lua_closeslot (lua_State *L, int idx) {
|
|||||||
StkId level;
|
StkId level;
|
||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
level = index2stack(L, idx);
|
level = index2stack(L, idx);
|
||||||
api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist.p == level,
|
api_check(L, (L->ci->callstatus & CIST_CLSRET) && L->tbclist.p == level,
|
||||||
"no variable to close at given level");
|
"no variable to close at given level");
|
||||||
level = luaF_close(L, level, CLOSEKTOP, 0);
|
level = luaF_close(L, level, CLOSEKTOP, 0);
|
||||||
setnilvalue(s2v(level));
|
setnilvalue(s2v(level));
|
||||||
@ -1287,9 +1287,7 @@ LUA_API void lua_toclose (lua_State *L, int idx) {
|
|||||||
nresults = L->ci->nresults;
|
nresults = L->ci->nresults;
|
||||||
api_check(L, L->tbclist.p < o, "given index below or equal a marked one");
|
api_check(L, L->tbclist.p < o, "given index below or equal a marked one");
|
||||||
luaF_newtbcupval(L, o); /* create new to-be-closed upvalue */
|
luaF_newtbcupval(L, o); /* create new to-be-closed upvalue */
|
||||||
if (!hastocloseCfunc(nresults)) /* function not marked yet? */
|
L->ci->callstatus |= CIST_CLSRET; /* mark that function has TBC slots */
|
||||||
L->ci->nresults = codeNresults(nresults); /* mark it */
|
|
||||||
lua_assert(hastocloseCfunc(L->ci->nresults));
|
|
||||||
lua_unlock(L);
|
lua_unlock(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
16
lapi.h
16
lapi.h
@ -62,20 +62,4 @@
|
|||||||
L->tbclist.p < L->top.p - (n), \
|
L->tbclist.p < L->top.p - (n), \
|
||||||
"not enough free elements in the stack")
|
"not enough free elements in the stack")
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** To reduce the overhead of returning from C functions, the presence of
|
|
||||||
** to-be-closed variables in these functions is coded in the CallInfo's
|
|
||||||
** field 'nresults', in a way that functions with no to-be-closed variables
|
|
||||||
** with zero, one, or "all" wanted results have no overhead. Functions
|
|
||||||
** with other number of wanted results, as well as functions with
|
|
||||||
** variables to be closed, have an extra check.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define hastocloseCfunc(n) ((n) < LUA_MULTRET)
|
|
||||||
|
|
||||||
/* Map [-1, inf) (range of 'nresults') into (-inf, -2] */
|
|
||||||
#define codeNresults(n) (-(n) - 3)
|
|
||||||
#define decodeNresults(n) (-(n) - 3)
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
20
ldo.c
20
ldo.c
@ -462,22 +462,23 @@ l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) {
|
|||||||
StkId firstresult;
|
StkId firstresult;
|
||||||
int i;
|
int i;
|
||||||
switch (wanted) { /* handle typical cases separately */
|
switch (wanted) { /* handle typical cases separately */
|
||||||
case 0: /* no values needed */
|
case 0 + 1: /* no values needed */
|
||||||
L->top.p = res;
|
L->top.p = res;
|
||||||
return;
|
return;
|
||||||
case 1: /* one value needed */
|
case 1 + 1: /* one value needed */
|
||||||
if (nres == 0) /* no results? */
|
if (nres == 0) /* no results? */
|
||||||
setnilvalue(s2v(res)); /* adjust with nil */
|
setnilvalue(s2v(res)); /* adjust with nil */
|
||||||
else /* at least one result */
|
else /* at least one result */
|
||||||
setobjs2s(L, res, L->top.p - nres); /* move it to proper place */
|
setobjs2s(L, res, L->top.p - nres); /* move it to proper place */
|
||||||
L->top.p = res + 1;
|
L->top.p = res + 1;
|
||||||
return;
|
return;
|
||||||
case LUA_MULTRET:
|
case LUA_MULTRET + 1:
|
||||||
wanted = nres; /* we want all results */
|
wanted = nres; /* we want all results */
|
||||||
break;
|
break;
|
||||||
default: /* two/more results and/or to-be-closed variables */
|
default: /* two/more results and/or to-be-closed variables */
|
||||||
if (hastocloseCfunc(wanted)) { /* to-be-closed variables? */
|
if (!(wanted & CIST_CLSRET))
|
||||||
L->ci->callstatus |= CIST_CLSRET; /* in case of yields */
|
wanted--;
|
||||||
|
else { /* to-be-closed variables? */
|
||||||
L->ci->u2.nres = nres;
|
L->ci->u2.nres = nres;
|
||||||
res = luaF_close(L, res, CLOSEKTOP, 1);
|
res = luaF_close(L, res, CLOSEKTOP, 1);
|
||||||
L->ci->callstatus &= ~CIST_CLSRET;
|
L->ci->callstatus &= ~CIST_CLSRET;
|
||||||
@ -486,7 +487,7 @@ l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) {
|
|||||||
rethook(L, L->ci, nres);
|
rethook(L, L->ci, nres);
|
||||||
res = restorestack(L, savedres); /* hook can move stack */
|
res = restorestack(L, savedres); /* hook can move stack */
|
||||||
}
|
}
|
||||||
wanted = decodeNresults(wanted);
|
wanted = (wanted & ~CIST_CLSRET) - 1;
|
||||||
if (wanted == LUA_MULTRET)
|
if (wanted == LUA_MULTRET)
|
||||||
wanted = nres; /* we want all results */
|
wanted = nres; /* we want all results */
|
||||||
}
|
}
|
||||||
@ -511,8 +512,10 @@ l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) {
|
|||||||
** that.
|
** that.
|
||||||
*/
|
*/
|
||||||
void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
|
void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
|
||||||
int wanted = ci->nresults;
|
int wanted = ci->nresults + 1;
|
||||||
if (l_unlikely(L->hookmask && !hastocloseCfunc(wanted)))
|
if (ci->callstatus & CIST_CLSRET)
|
||||||
|
wanted |= CIST_CLSRET; /* don't check hook in this case */
|
||||||
|
else if (l_unlikely(L->hookmask))
|
||||||
rethook(L, ci, nres);
|
rethook(L, ci, nres);
|
||||||
/* move results to proper place */
|
/* move results to proper place */
|
||||||
moveresults(L, ci->func.p, nres, wanted);
|
moveresults(L, ci->func.p, nres, wanted);
|
||||||
@ -736,7 +739,6 @@ static int finishpcallk (lua_State *L, CallInfo *ci) {
|
|||||||
static void finishCcall (lua_State *L, CallInfo *ci) {
|
static void finishCcall (lua_State *L, CallInfo *ci) {
|
||||||
int n; /* actual number of results from C function */
|
int n; /* actual number of results from C function */
|
||||||
if (ci->callstatus & CIST_CLSRET) { /* was returning? */
|
if (ci->callstatus & CIST_CLSRET) { /* was returning? */
|
||||||
lua_assert(hastocloseCfunc(ci->nresults));
|
|
||||||
n = ci->u2.nres; /* just redo 'luaD_poscall' */
|
n = ci->u2.nres; /* just redo 'luaD_poscall' */
|
||||||
/* don't need to reset CIST_CLSRET, as it will be set again anyway */
|
/* don't need to reset CIST_CLSRET, as it will be set again anyway */
|
||||||
}
|
}
|
||||||
|
@ -165,6 +165,23 @@ do -- test returning more results than fit in the caller stack
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
do -- testing multipe returns
|
||||||
|
local function foo (n)
|
||||||
|
if n > 0 then return n, foo(n - 1) end
|
||||||
|
end
|
||||||
|
|
||||||
|
local t = {T.testC("call 1 10; return 10", foo, 20)}
|
||||||
|
assert(t[1] == 20 and t[10] == 11 and t[11] == nil)
|
||||||
|
|
||||||
|
local t = table.pack(T.testC("call 1 10; return 10", foo, 2))
|
||||||
|
assert(t[1] == 2 and t[2] == 1 and t[3] == nil and t.n == 10)
|
||||||
|
|
||||||
|
local t = {T.testC([[
|
||||||
|
checkstack 300 "error"; call 1 250; return 250]], foo, 250)}
|
||||||
|
assert(t[1] == 250 and t[250] == 1 and t[251] == nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-- testing globals
|
-- testing globals
|
||||||
_G.AA = 14; _G.BB = "a31"
|
_G.AA = 14; _G.BB = "a31"
|
||||||
local a = {T.testC[[
|
local a = {T.testC[[
|
||||||
|
Loading…
Reference in New Issue
Block a user