aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2024-07-19 17:34:22 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2024-07-19 17:34:22 -0300
commitf407b3c4a1bc9667867ec51e835c20d97aab55a2 (patch)
treead629983fbde70d5446411d765a99a1b724eb82b
parenta546138d158d79d44b2c5b42630be00d306f4e7c (diff)
downloadlua-f407b3c4a1bc9667867ec51e835c20d97aab55a2.tar.gz
lua-f407b3c4a1bc9667867ec51e835c20d97aab55a2.tar.bz2
lua-f407b3c4a1bc9667867ec51e835c20d97aab55a2.zip
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.
-rw-r--r--lapi.c8
-rw-r--r--lapi.h16
-rw-r--r--ldo.c20
-rw-r--r--testes/api.lua17
4 files changed, 31 insertions, 30 deletions
diff --git a/lapi.c b/lapi.c
index dbd291d7..70e2a44a 100644
--- a/lapi.c
+++ b/lapi.c
@@ -207,7 +207,7 @@ LUA_API void lua_settop (lua_State *L, int idx) {
207 } 207 }
208 newtop = L->top.p + diff; 208 newtop = L->top.p + diff;
209 if (diff < 0 && L->tbclist.p >= newtop) { 209 if (diff < 0 && L->tbclist.p >= newtop) {
210 lua_assert(hastocloseCfunc(ci->nresults)); 210 lua_assert(ci->callstatus & CIST_CLSRET);
211 newtop = luaF_close(L, newtop, CLOSEKTOP, 0); 211 newtop = luaF_close(L, newtop, CLOSEKTOP, 0);
212 } 212 }
213 L->top.p = newtop; /* correct top only after closing any upvalue */ 213 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) {
219 StkId level; 219 StkId level;
220 lua_lock(L); 220 lua_lock(L);
221 level = index2stack(L, idx); 221 level = index2stack(L, idx);
222 api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist.p == level, 222 api_check(L, (L->ci->callstatus & CIST_CLSRET) && L->tbclist.p == level,
223 "no variable to close at given level"); 223 "no variable to close at given level");
224 level = luaF_close(L, level, CLOSEKTOP, 0); 224 level = luaF_close(L, level, CLOSEKTOP, 0);
225 setnilvalue(s2v(level)); 225 setnilvalue(s2v(level));
@@ -1287,9 +1287,7 @@ LUA_API void lua_toclose (lua_State *L, int idx) {
1287 nresults = L->ci->nresults; 1287 nresults = L->ci->nresults;
1288 api_check(L, L->tbclist.p < o, "given index below or equal a marked one"); 1288 api_check(L, L->tbclist.p < o, "given index below or equal a marked one");
1289 luaF_newtbcupval(L, o); /* create new to-be-closed upvalue */ 1289 luaF_newtbcupval(L, o); /* create new to-be-closed upvalue */
1290 if (!hastocloseCfunc(nresults)) /* function not marked yet? */ 1290 L->ci->callstatus |= CIST_CLSRET; /* mark that function has TBC slots */
1291 L->ci->nresults = codeNresults(nresults); /* mark it */
1292 lua_assert(hastocloseCfunc(L->ci->nresults));
1293 lua_unlock(L); 1291 lua_unlock(L);
1294} 1292}
1295 1293
diff --git a/lapi.h b/lapi.h
index 21be4a24..9b545344 100644
--- a/lapi.h
+++ b/lapi.h
@@ -62,20 +62,4 @@
62 L->tbclist.p < L->top.p - (n), \ 62 L->tbclist.p < L->top.p - (n), \
63 "not enough free elements in the stack") 63 "not enough free elements in the stack")
64 64
65
66/*
67** To reduce the overhead of returning from C functions, the presence of
68** to-be-closed variables in these functions is coded in the CallInfo's
69** field 'nresults', in a way that functions with no to-be-closed variables
70** with zero, one, or "all" wanted results have no overhead. Functions
71** with other number of wanted results, as well as functions with
72** variables to be closed, have an extra check.
73*/
74
75#define hastocloseCfunc(n) ((n) < LUA_MULTRET)
76
77/* Map [-1, inf) (range of 'nresults') into (-inf, -2] */
78#define codeNresults(n) (-(n) - 3)
79#define decodeNresults(n) (-(n) - 3)
80
81#endif 65#endif
diff --git a/ldo.c b/ldo.c
index 34101ba3..6eaa31a0 100644
--- a/ldo.c
+++ b/ldo.c
@@ -462,22 +462,23 @@ l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) {
462 StkId firstresult; 462 StkId firstresult;
463 int i; 463 int i;
464 switch (wanted) { /* handle typical cases separately */ 464 switch (wanted) { /* handle typical cases separately */
465 case 0: /* no values needed */ 465 case 0 + 1: /* no values needed */
466 L->top.p = res; 466 L->top.p = res;
467 return; 467 return;
468 case 1: /* one value needed */ 468 case 1 + 1: /* one value needed */
469 if (nres == 0) /* no results? */ 469 if (nres == 0) /* no results? */
470 setnilvalue(s2v(res)); /* adjust with nil */ 470 setnilvalue(s2v(res)); /* adjust with nil */
471 else /* at least one result */ 471 else /* at least one result */
472 setobjs2s(L, res, L->top.p - nres); /* move it to proper place */ 472 setobjs2s(L, res, L->top.p - nres); /* move it to proper place */
473 L->top.p = res + 1; 473 L->top.p = res + 1;
474 return; 474 return;
475 case LUA_MULTRET: 475 case LUA_MULTRET + 1:
476 wanted = nres; /* we want all results */ 476 wanted = nres; /* we want all results */
477 break; 477 break;
478 default: /* two/more results and/or to-be-closed variables */ 478 default: /* two/more results and/or to-be-closed variables */
479 if (hastocloseCfunc(wanted)) { /* to-be-closed variables? */ 479 if (!(wanted & CIST_CLSRET))
480 L->ci->callstatus |= CIST_CLSRET; /* in case of yields */ 480 wanted--;
481 else { /* to-be-closed variables? */
481 L->ci->u2.nres = nres; 482 L->ci->u2.nres = nres;
482 res = luaF_close(L, res, CLOSEKTOP, 1); 483 res = luaF_close(L, res, CLOSEKTOP, 1);
483 L->ci->callstatus &= ~CIST_CLSRET; 484 L->ci->callstatus &= ~CIST_CLSRET;
@@ -486,7 +487,7 @@ l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) {
486 rethook(L, L->ci, nres); 487 rethook(L, L->ci, nres);
487 res = restorestack(L, savedres); /* hook can move stack */ 488 res = restorestack(L, savedres); /* hook can move stack */
488 } 489 }
489 wanted = decodeNresults(wanted); 490 wanted = (wanted & ~CIST_CLSRET) - 1;
490 if (wanted == LUA_MULTRET) 491 if (wanted == LUA_MULTRET)
491 wanted = nres; /* we want all results */ 492 wanted = nres; /* we want all results */
492 } 493 }
@@ -511,8 +512,10 @@ l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) {
511** that. 512** that.
512*/ 513*/
513void luaD_poscall (lua_State *L, CallInfo *ci, int nres) { 514void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
514 int wanted = ci->nresults; 515 int wanted = ci->nresults + 1;
515 if (l_unlikely(L->hookmask && !hastocloseCfunc(wanted))) 516 if (ci->callstatus & CIST_CLSRET)
517 wanted |= CIST_CLSRET; /* don't check hook in this case */
518 else if (l_unlikely(L->hookmask))
516 rethook(L, ci, nres); 519 rethook(L, ci, nres);
517 /* move results to proper place */ 520 /* move results to proper place */
518 moveresults(L, ci->func.p, nres, wanted); 521 moveresults(L, ci->func.p, nres, wanted);
@@ -736,7 +739,6 @@ static int finishpcallk (lua_State *L, CallInfo *ci) {
736static void finishCcall (lua_State *L, CallInfo *ci) { 739static void finishCcall (lua_State *L, CallInfo *ci) {
737 int n; /* actual number of results from C function */ 740 int n; /* actual number of results from C function */
738 if (ci->callstatus & CIST_CLSRET) { /* was returning? */ 741 if (ci->callstatus & CIST_CLSRET) { /* was returning? */
739 lua_assert(hastocloseCfunc(ci->nresults));
740 n = ci->u2.nres; /* just redo 'luaD_poscall' */ 742 n = ci->u2.nres; /* just redo 'luaD_poscall' */
741 /* don't need to reset CIST_CLSRET, as it will be set again anyway */ 743 /* don't need to reset CIST_CLSRET, as it will be set again anyway */
742 } 744 }
diff --git a/testes/api.lua b/testes/api.lua
index dc485240..ae2f82dd 100644
--- a/testes/api.lua
+++ b/testes/api.lua
@@ -165,6 +165,23 @@ do -- test returning more results than fit in the caller stack
165end 165end
166 166
167 167
168do -- testing multipe returns
169 local function foo (n)
170 if n > 0 then return n, foo(n - 1) end
171 end
172
173 local t = {T.testC("call 1 10; return 10", foo, 20)}
174 assert(t[1] == 20 and t[10] == 11 and t[11] == nil)
175
176 local t = table.pack(T.testC("call 1 10; return 10", foo, 2))
177 assert(t[1] == 2 and t[2] == 1 and t[3] == nil and t.n == 10)
178
179 local t = {T.testC([[
180 checkstack 300 "error"; call 1 250; return 250]], foo, 250)}
181 assert(t[1] == 250 and t[250] == 1 and t[251] == nil)
182end
183
184
168-- testing globals 185-- testing globals
169_G.AA = 14; _G.BB = "a31" 186_G.AA = 14; _G.BB = "a31"
170local a = {T.testC[[ 187local a = {T.testC[[