diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2024-07-19 17:34:22 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2024-07-19 17:34:22 -0300 |
commit | f407b3c4a1bc9667867ec51e835c20d97aab55a2 (patch) | |
tree | ad629983fbde70d5446411d765a99a1b724eb82b | |
parent | a546138d158d79d44b2c5b42630be00d306f4e7c (diff) | |
download | lua-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.c | 8 | ||||
-rw-r--r-- | lapi.h | 16 | ||||
-rw-r--r-- | ldo.c | 20 | ||||
-rw-r--r-- | testes/api.lua | 17 |
4 files changed, 31 insertions, 30 deletions
@@ -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 | ||
@@ -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 |
@@ -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 | */ |
513 | void luaD_poscall (lua_State *L, CallInfo *ci, int nres) { | 514 | void 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) { | |||
736 | static void finishCcall (lua_State *L, CallInfo *ci) { | 739 | static 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 | |||
165 | end | 165 | end |
166 | 166 | ||
167 | 167 | ||
168 | do -- 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) | ||
182 | end | ||
183 | |||
184 | |||
168 | -- testing globals | 185 | -- testing globals |
169 | _G.AA = 14; _G.BB = "a31" | 186 | _G.AA = 14; _G.BB = "a31" |
170 | local a = {T.testC[[ | 187 | local a = {T.testC[[ |