|
@@ -408,24 +408,27 @@ static void moveresults (lua_State *L, StkId res, int nres, int wanted) {
|
|
case LUA_MULTRET:
|
|
case LUA_MULTRET:
|
|
wanted = nres; /* we want all results */
|
|
wanted = nres; /* we want all results */
|
|
break;
|
|
break;
|
|
- default: /* multiple results (or to-be-closed variables) */
|
|
|
|
|
|
+ default: /* two/more results and/or to-be-closed variables */
|
|
if (hastocloseCfunc(wanted)) { /* to-be-closed variables? */
|
|
if (hastocloseCfunc(wanted)) { /* to-be-closed variables? */
|
|
ptrdiff_t savedres = savestack(L, res);
|
|
ptrdiff_t savedres = savestack(L, res);
|
|
- luaF_close(L, res, CLOSEKTOP, 0); /* may change the stack */
|
|
|
|
- wanted = codeNresults(wanted); /* correct value */
|
|
|
|
- if (wanted == LUA_MULTRET)
|
|
|
|
- wanted = nres;
|
|
|
|
|
|
+ L->ci->callstatus |= CIST_CLSRET; /* in case of yields */
|
|
|
|
+ L->ci->u2.nres = nres;
|
|
|
|
+ luaF_close(L, res, CLOSEKTOP, 1);
|
|
|
|
+ L->ci->callstatus &= ~CIST_CLSRET;
|
|
if (L->hookmask) /* if needed, call hook after '__close's */
|
|
if (L->hookmask) /* if needed, call hook after '__close's */
|
|
rethook(L, L->ci, nres);
|
|
rethook(L, L->ci, nres);
|
|
res = restorestack(L, savedres); /* close and hook can move stack */
|
|
res = restorestack(L, savedres); /* close and hook can move stack */
|
|
|
|
+ wanted = decodeNresults(wanted);
|
|
|
|
+ if (wanted == LUA_MULTRET)
|
|
|
|
+ wanted = nres; /* we want all results */
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
+ /* generic case */
|
|
firstresult = L->top - nres; /* index of first result */
|
|
firstresult = L->top - nres; /* index of first result */
|
|
- /* move all results to correct place */
|
|
|
|
- if (nres > wanted)
|
|
|
|
- nres = wanted; /* don't need more than that */
|
|
|
|
- for (i = 0; i < nres; i++)
|
|
|
|
|
|
+ if (nres > wanted) /* extra results? */
|
|
|
|
+ nres = wanted; /* don't need them */
|
|
|
|
+ for (i = 0; i < nres; i++) /* move all results to correct place */
|
|
setobjs2s(L, res + i, firstresult + i);
|
|
setobjs2s(L, res + i, firstresult + i);
|
|
for (; i < wanted; i++) /* complete wanted number of results */
|
|
for (; i < wanted; i++) /* complete wanted number of results */
|
|
setnilvalue(s2v(res + i));
|
|
setnilvalue(s2v(res + i));
|
|
@@ -445,6 +448,9 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
|
|
rethook(L, ci, nres);
|
|
rethook(L, ci, nres);
|
|
/* move results to proper place */
|
|
/* move results to proper place */
|
|
moveresults(L, ci->func, nres, wanted);
|
|
moveresults(L, ci->func, nres, wanted);
|
|
|
|
+ /* function cannot be in any of these cases when returning */
|
|
|
|
+ lua_assert(!(ci->callstatus &
|
|
|
|
+ (CIST_HOOKED | CIST_YPCALL | CIST_FIN | CIST_TRAN | CIST_CLSRET)));
|
|
L->ci = ci->previous; /* back to caller (after closing variables) */
|
|
L->ci = ci->previous; /* back to caller (after closing variables) */
|
|
}
|
|
}
|
|
|
|
|
|
@@ -615,28 +621,36 @@ static int finishpcallk (lua_State *L, CallInfo *ci) {
|
|
|
|
|
|
/*
|
|
/*
|
|
** Completes the execution of a C function interrupted by an yield.
|
|
** Completes the execution of a C function interrupted by an yield.
|
|
-** The interruption must have happened while the function was
|
|
|
|
-** executing 'lua_callk' or 'lua_pcallk'. In the second case, the
|
|
|
|
-** call to 'finishpcallk' finishes the interrupted execution of
|
|
|
|
-** 'lua_pcallk'. After that, it calls the continuation of the
|
|
|
|
-** interrupted function and finally it completes the job of the
|
|
|
|
-** 'luaD_call' that called the function.
|
|
|
|
-** In the call to 'adjustresults', we do not know the number of
|
|
|
|
-** results of the function called by 'lua_callk'/'lua_pcallk',
|
|
|
|
-** so we are conservative and use LUA_MULTRET (always adjust).
|
|
|
|
|
|
+** The interruption must have happened while the function was either
|
|
|
|
+** closing its tbc variables in 'moveresults' or executing
|
|
|
|
+** 'lua_callk'/'lua_pcallk'. In the first case, it just redoes
|
|
|
|
+** 'luaD_poscall'. In the second case, the call to 'finishpcallk'
|
|
|
|
+** finishes the interrupted execution of 'lua_pcallk'. After that, it
|
|
|
|
+** calls the continuation of the interrupted function and finally it
|
|
|
|
+** completes the job of the 'luaD_call' that called the function. In
|
|
|
|
+** the call to 'adjustresults', we do not know the number of results
|
|
|
|
+** of the function called by 'lua_callk'/'lua_pcallk', so we are
|
|
|
|
+** conservative and use LUA_MULTRET (always adjust).
|
|
*/
|
|
*/
|
|
static void finishCcall (lua_State *L, CallInfo *ci) {
|
|
static void finishCcall (lua_State *L, CallInfo *ci) {
|
|
- int n;
|
|
|
|
- int status = LUA_YIELD; /* default if there were no errors */
|
|
|
|
- /* must have a continuation and must be able to call it */
|
|
|
|
- lua_assert(ci->u.c.k != NULL && yieldable(L));
|
|
|
|
- if (ci->callstatus & CIST_YPCALL) /* was inside a 'lua_pcallk'? */
|
|
|
|
- status = finishpcallk(L, ci); /* finish it */
|
|
|
|
- adjustresults(L, LUA_MULTRET); /* finish 'lua_callk' */
|
|
|
|
- lua_unlock(L);
|
|
|
|
- n = (*ci->u.c.k)(L, status, ci->u.c.ctx); /* call continuation */
|
|
|
|
- lua_lock(L);
|
|
|
|
- api_checknelems(L, n);
|
|
|
|
|
|
+ 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 */
|
|
|
|
+ }
|
|
|
|
+ else {
|
|
|
|
+ int status = LUA_YIELD; /* default if there were no errors */
|
|
|
|
+ /* must have a continuation and must be able to call it */
|
|
|
|
+ lua_assert(ci->u.c.k != NULL && yieldable(L));
|
|
|
|
+ if (ci->callstatus & CIST_YPCALL) /* was inside a 'lua_pcallk'? */
|
|
|
|
+ status = finishpcallk(L, ci); /* finish it */
|
|
|
|
+ adjustresults(L, LUA_MULTRET); /* finish 'lua_callk' */
|
|
|
|
+ lua_unlock(L);
|
|
|
|
+ n = (*ci->u.c.k)(L, status, ci->u.c.ctx); /* call continuation */
|
|
|
|
+ lua_lock(L);
|
|
|
|
+ api_checknelems(L, n);
|
|
|
|
+ }
|
|
luaD_poscall(L, ci, n); /* finish 'luaD_call' */
|
|
luaD_poscall(L, ci, n); /* finish 'luaD_call' */
|
|
}
|
|
}
|
|
|
|
|