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;
|
||||
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);
|
||||
}
|
||||
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;
|
||||
lua_lock(L);
|
||||
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");
|
||||
level = luaF_close(L, level, CLOSEKTOP, 0);
|
||||
setnilvalue(s2v(level));
|
||||
@ -1287,9 +1287,7 @@ LUA_API void lua_toclose (lua_State *L, int idx) {
|
||||
nresults = L->ci->nresults;
|
||||
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 */
|
||||
if (!hastocloseCfunc(nresults)) /* function not marked yet? */
|
||||
L->ci->nresults = codeNresults(nresults); /* mark it */
|
||||
lua_assert(hastocloseCfunc(L->ci->nresults));
|
||||
L->ci->callstatus |= CIST_CLSRET; /* mark that function has TBC slots */
|
||||
lua_unlock(L);
|
||||
}
|
||||
|
||||
|
16
lapi.h
16
lapi.h
@ -62,20 +62,4 @@
|
||||
L->tbclist.p < L->top.p - (n), \
|
||||
"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
|
||||
|
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;
|
||||
int i;
|
||||
switch (wanted) { /* handle typical cases separately */
|
||||
case 0: /* no values needed */
|
||||
case 0 + 1: /* no values needed */
|
||||
L->top.p = res;
|
||||
return;
|
||||
case 1: /* one value needed */
|
||||
case 1 + 1: /* one value needed */
|
||||
if (nres == 0) /* no results? */
|
||||
setnilvalue(s2v(res)); /* adjust with nil */
|
||||
else /* at least one result */
|
||||
setobjs2s(L, res, L->top.p - nres); /* move it to proper place */
|
||||
L->top.p = res + 1;
|
||||
return;
|
||||
case LUA_MULTRET:
|
||||
case LUA_MULTRET + 1:
|
||||
wanted = nres; /* we want all results */
|
||||
break;
|
||||
default: /* two/more results and/or to-be-closed variables */
|
||||
if (hastocloseCfunc(wanted)) { /* to-be-closed variables? */
|
||||
L->ci->callstatus |= CIST_CLSRET; /* in case of yields */
|
||||
if (!(wanted & CIST_CLSRET))
|
||||
wanted--;
|
||||
else { /* to-be-closed variables? */
|
||||
L->ci->u2.nres = nres;
|
||||
res = luaF_close(L, res, CLOSEKTOP, 1);
|
||||
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);
|
||||
res = restorestack(L, savedres); /* hook can move stack */
|
||||
}
|
||||
wanted = decodeNresults(wanted);
|
||||
wanted = (wanted & ~CIST_CLSRET) - 1;
|
||||
if (wanted == LUA_MULTRET)
|
||||
wanted = nres; /* we want all results */
|
||||
}
|
||||
@ -511,8 +512,10 @@ l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) {
|
||||
** that.
|
||||
*/
|
||||
void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
|
||||
int wanted = ci->nresults;
|
||||
if (l_unlikely(L->hookmask && !hastocloseCfunc(wanted)))
|
||||
int wanted = ci->nresults + 1;
|
||||
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);
|
||||
/* move results to proper place */
|
||||
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) {
|
||||
int n; /* actual number of results from C function */
|
||||
if (ci->callstatus & CIST_CLSRET) { /* was returning? */
|
||||
lua_assert(hastocloseCfunc(ci->nresults));
|
||||
n = ci->u2.nres; /* just redo 'luaD_poscall' */
|
||||
/* 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
|
||||
|
||||
|
||||
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
|
||||
_G.AA = 14; _G.BB = "a31"
|
||||
local a = {T.testC[[
|
||||
|
Loading…
Reference in New Issue
Block a user