From 236bcc6e10f59b9336603571f1683cbe4aa411a9 Mon Sep 17 00:00:00 2001 From: Li Jin Date: Fri, 22 Jan 2021 17:54:39 +0800 Subject: update included Lua. --- src/lua/lapi.c | 21 ++++++++- src/lua/lauxlib.c | 8 ++-- src/lua/lcorolib.c | 7 ++- src/lua/ldebug.c | 23 +++++++--- src/lua/ldebug.h | 1 + src/lua/ldo.c | 125 ++++++++++++++++++++++++++++++++++++++--------------- src/lua/ldo.h | 1 + src/lua/lfunc.c | 117 ++++++++++++++++++++----------------------------- src/lua/lfunc.h | 6 +-- src/lua/lobject.h | 3 +- src/lua/lstate.c | 32 ++++++++------ src/lua/lstate.h | 1 + src/lua/lstrlib.c | 70 +++++++++++++++++------------- src/lua/ltable.c | 2 + src/lua/lua.h | 3 +- src/lua/lvm.c | 10 +++-- 16 files changed, 261 insertions(+), 169 deletions(-) diff --git a/src/lua/lapi.c b/src/lua/lapi.c index 03e756d..3583e9c 100644 --- a/src/lua/lapi.c +++ b/src/lua/lapi.c @@ -187,9 +187,26 @@ LUA_API void lua_settop (lua_State *L, int idx) { api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top"); diff = idx + 1; /* will "subtract" index (as it is negative) */ } +#if defined(LUA_COMPAT_5_4_0) if (diff < 0 && hastocloseCfunc(ci->nresults)) - luaF_close(L, L->top + diff, LUA_OK); - L->top += diff; /* correct top only after closing any upvalue */ + luaF_close(L, L->top + diff, CLOSEKTOP, 0); +#endif + L->top += diff; + api_check(L, L->openupval == NULL || uplevel(L->openupval) < L->top, + "cannot pop an unclosed slot"); + lua_unlock(L); +} + + +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->openupval != NULL && + uplevel(L->openupval) == level, + "no variable to close at given level"); + luaF_close(L, level, CLOSEKTOP, 0); + setnilvalue(s2v(level)); lua_unlock(L); } diff --git a/src/lua/lauxlib.c b/src/lua/lauxlib.c index 074ff08..e8fc486 100644 --- a/src/lua/lauxlib.c +++ b/src/lua/lauxlib.c @@ -545,10 +545,8 @@ static char *prepbuffsize (luaL_Buffer *B, size_t sz, int boxidx) { if (buffonstack(B)) /* buffer already has a box? */ newbuff = (char *)resizebox(L, boxidx, newsize); /* resize it */ else { /* no box yet */ - lua_pushnil(L); /* reserve slot for final result */ newbox(L); /* create a new box */ - /* move box (and slot) to its intended position */ - lua_rotate(L, boxidx - 1, 2); + lua_insert(L, boxidx); /* move box to its intended position */ lua_toclose(L, boxidx); newbuff = (char *)resizebox(L, boxidx, newsize); memcpy(newbuff, B->b, B->n * sizeof(char)); /* copy original content */ @@ -585,8 +583,8 @@ LUALIB_API void luaL_pushresult (luaL_Buffer *B) { lua_State *L = B->L; lua_pushlstring(L, B->b, B->n); if (buffonstack(B)) { - lua_copy(L, -1, -3); /* move string to reserved slot */ - lua_pop(L, 2); /* pop string and box (closing the box) */ + lua_closeslot(L, -2); /* close the box */ + lua_remove(L, -2); /* remove box from the stack */ } } diff --git a/src/lua/lcorolib.c b/src/lua/lcorolib.c index c165031..ed7c58b 100644 --- a/src/lua/lcorolib.c +++ b/src/lua/lcorolib.c @@ -75,8 +75,11 @@ static int luaB_auxwrap (lua_State *L) { int r = auxresume(L, co, lua_gettop(L)); if (r < 0) { /* error? */ int stat = lua_status(co); - if (stat != LUA_OK && stat != LUA_YIELD) /* error in the coroutine? */ - lua_resetthread(co); /* close its tbc variables */ + if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */ + stat = lua_resetthread(co); /* close its tbc variables */ + lua_assert(stat != LUA_OK); + lua_xmove(co, L, 1); /* copy error message */ + } if (stat != LUA_ERRMEM && /* not a memory error and ... */ lua_type(L, -1) == LUA_TSTRING) { /* ... error object is a string? */ luaL_where(L, 1); /* add extra info, if available */ diff --git a/src/lua/ldebug.c b/src/lua/ldebug.c index 8cb00e5..819550d 100644 --- a/src/lua/ldebug.c +++ b/src/lua/ldebug.c @@ -629,12 +629,10 @@ static const char *funcnamefromcode (lua_State *L, CallInfo *ci, case OP_LEN: tm = TM_LEN; break; case OP_CONCAT: tm = TM_CONCAT; break; case OP_EQ: tm = TM_EQ; break; - case OP_LT: case OP_LE: case OP_LTI: case OP_LEI: - *name = "order"; /* '<=' can call '__lt', etc. */ - return "metamethod"; - case OP_CLOSE: case OP_RETURN: - *name = "close"; - return "metamethod"; + /* no cases for OP_EQI and OP_EQK, as they don't call metamethods */ + case OP_LT: case OP_LTI: case OP_GTI: tm = TM_LT; break; + case OP_LE: case OP_LEI: case OP_GEI: tm = TM_LE; break; + case OP_CLOSE: case OP_RETURN: tm = TM_CLOSE; break; default: return NULL; /* cannot find a reasonable name */ } @@ -697,6 +695,19 @@ l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) { } +l_noret luaG_callerror (lua_State *L, const TValue *o) { + CallInfo *ci = L->ci; + const char *name = NULL; /* to avoid warnings */ + const char *what = (isLua(ci)) ? funcnamefromcode(L, ci, &name) : NULL; + if (what != NULL) { + const char *t = luaT_objtypename(L, o); + luaG_runerror(L, "%s '%s' is not callable (a %s value)", what, name, t); + } + else + luaG_typeerror(L, o, "call"); +} + + l_noret luaG_forerror (lua_State *L, const TValue *o, const char *what) { luaG_runerror(L, "bad 'for' %s (number expected, got %s)", what, luaT_objtypename(L, o)); diff --git a/src/lua/ldebug.h b/src/lua/ldebug.h index a0a5848..55b3ae0 100644 --- a/src/lua/ldebug.h +++ b/src/lua/ldebug.h @@ -31,6 +31,7 @@ LUAI_FUNC const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos); LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *opname); +LUAI_FUNC l_noret luaG_callerror (lua_State *L, const TValue *o); LUAI_FUNC l_noret luaG_forerror (lua_State *L, const TValue *o, const char *what); LUAI_FUNC l_noret luaG_concaterror (lua_State *L, const TValue *p1, diff --git a/src/lua/ldo.c b/src/lua/ldo.c index 4b55c31..aa159cf 100644 --- a/src/lua/ldo.c +++ b/src/lua/ldo.c @@ -98,11 +98,12 @@ void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) { setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); break; } - case CLOSEPROTECT: { + case LUA_OK: { /* special case only for closing upvalues */ setnilvalue(s2v(oldtop)); /* no error message */ break; } default: { + lua_assert(errorstatus(errcode)); /* real error */ setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ break; } @@ -118,17 +119,13 @@ l_noret luaD_throw (lua_State *L, int errcode) { } else { /* thread has no error handler */ global_State *g = G(L); - errcode = luaF_close(L, L->stack, errcode); /* close all upvalues */ - L->status = cast_byte(errcode); /* mark it as dead */ + errcode = luaE_resetthread(L, errcode); /* close all upvalues */ if (g->mainthread->errorJmp) { /* main thread has a handler? */ setobjs2s(L, g->mainthread->top++, L->top - 1); /* copy error obj. */ luaD_throw(g->mainthread, errcode); /* re-throw in main thread */ } else { /* no handler at all; abort */ if (g->panic) { /* panic function? */ - luaD_seterrorobj(L, errcode, L->top); /* assume EXTRA_STACK */ - if (L->ci->top < L->top) - L->ci->top = L->top; /* pushing msg. can break this invariant */ lua_unlock(L); g->panic(L); /* call panic function (last chance to jump out) */ } @@ -375,7 +372,7 @@ void luaD_tryfuncTM (lua_State *L, StkId func) { const TValue *tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); StkId p; if (unlikely(ttisnil(tm))) - luaG_typeerror(L, s2v(func), "call"); /* nothing to call */ + luaG_callerror(L, s2v(func)); /* nothing to call */ for (p = L->top; p > func; p--) /* open space for metamethod */ setobjs2s(L, p, p-1); L->top++; /* stack space pre-allocated by the caller */ @@ -409,7 +406,7 @@ static void moveresults (lua_State *L, StkId res, int nres, int wanted) { default: /* multiple results (or to-be-closed variables) */ if (hastocloseCfunc(wanted)) { /* to-be-closed variables? */ ptrdiff_t savedres = savestack(L, res); - luaF_close(L, res, LUA_OK); /* may change the stack */ + luaF_close(L, res, CLOSEKTOP, 0); /* may change the stack */ res = restorestack(L, savedres); wanted = codeNresults(wanted); /* correct value */ if (wanted == LUA_MULTRET) @@ -596,15 +593,11 @@ static void finishCcall (lua_State *L, int status) { /* ** Executes "full continuation" (everything in the stack) of a ** previously interrupted coroutine until the stack is empty (or another -** interruption long-jumps out of the loop). If the coroutine is -** recovering from an error, 'ud' points to the error status, which must -** be passed to the first continuation function (otherwise the default -** status is LUA_YIELD). +** interruption long-jumps out of the loop). */ static void unroll (lua_State *L, void *ud) { CallInfo *ci; - if (ud != NULL) /* error status? */ - finishCcall(L, *(int *)ud); /* finish 'lua_pcallk' callee */ + UNUSED(ud); while ((ci = L->ci) != &L->base_ci) { /* something in the stack */ if (!isLua(ci)) /* C function? */ finishCcall(L, LUA_YIELD); /* complete its execution */ @@ -631,24 +624,36 @@ static CallInfo *findpcall (lua_State *L) { /* -** Recovers from an error in a coroutine. Finds a recover point (if -** there is one) and completes the execution of the interrupted -** 'luaD_pcall'. If there is no recover point, returns zero. +** Auxiliary structure to call 'recover' in protected mode. */ -static int recover (lua_State *L, int status) { - StkId oldtop; - CallInfo *ci = findpcall(L); - if (ci == NULL) return 0; /* no recovery point */ +struct RecoverS { + int status; + CallInfo *ci; +}; + + +/* +** Recovers from an error in a coroutine: completes the execution of the +** interrupted 'luaD_pcall', completes the interrupted C function which +** called 'lua_pcallk', and continues running the coroutine. If there is +** an error in 'luaF_close', this function will be called again and the +** coroutine will continue from where it left. +*/ +static void recover (lua_State *L, void *ud) { + struct RecoverS *r = cast(struct RecoverS *, ud); + int status = r->status; + CallInfo *ci = r->ci; /* recover point */ + StkId func = restorestack(L, ci->u2.funcidx); /* "finish" luaD_pcall */ - oldtop = restorestack(L, ci->u2.funcidx); L->ci = ci; L->allowhook = getoah(ci->callstatus); /* restore original 'allowhook' */ - status = luaF_close(L, oldtop, status); /* may change the stack */ - oldtop = restorestack(L, ci->u2.funcidx); - luaD_seterrorobj(L, status, oldtop); + luaF_close(L, func, status, 0); /* may change the stack */ + func = restorestack(L, ci->u2.funcidx); + luaD_seterrorobj(L, status, func); luaD_shrinkstack(L); /* restore stack size in case of overflow */ L->errfunc = ci->u.c.old_errfunc; - return 1; /* continue running the coroutine */ + finishCcall(L, status); /* finish 'lua_pcallk' callee */ + unroll(L, NULL); /* continue running the coroutine */ } @@ -698,6 +703,24 @@ static void resume (lua_State *L, void *ud) { } } + +/* +** Calls 'recover' in protected mode, repeating while there are +** recoverable errors, that is, errors inside a protected call. (Any +** error interrupts 'recover', and this loop protects it again so it +** can continue.) Stops with a normal end (status == LUA_OK), an yield +** (status == LUA_YIELD), or an unprotected error ('findpcall' doesn't +** find a recover point). +*/ +static int p_recover (lua_State *L, int status) { + struct RecoverS r; + r.status = status; + while (errorstatus(status) && (r.ci = findpcall(L)) != NULL) + r.status = luaD_rawrunprotected(L, recover, &r); + return r.status; +} + + LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs, int *nresults) { int status; @@ -715,10 +738,7 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs, api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); status = luaD_rawrunprotected(L, resume, &nargs); /* continue running after recoverable errors */ - while (errorstatus(status) && recover(L, status)) { - /* unroll continuation */ - status = luaD_rawrunprotected(L, unroll, &status); - } + status = p_recover(L, status); if (likely(!errorstatus(status))) lua_assert(status == L->status); /* normal end or yield */ else { /* unrecoverable error */ @@ -769,6 +789,45 @@ LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx, } +/* +** Auxiliary structure to call 'luaF_close' in protected mode. +*/ +struct CloseP { + StkId level; + int status; +}; + + +/* +** Auxiliary function to call 'luaF_close' in protected mode. +*/ +static void closepaux (lua_State *L, void *ud) { + struct CloseP *pcl = cast(struct CloseP *, ud); + luaF_close(L, pcl->level, pcl->status, 0); +} + + +/* +** Calls 'luaF_close' in protected mode. Return the original status +** or, in case of errors, the new status. +*/ +int luaD_closeprotected (lua_State *L, ptrdiff_t level, int status) { + CallInfo *old_ci = L->ci; + lu_byte old_allowhooks = L->allowhook; + for (;;) { /* keep closing upvalues until no more errors */ + struct CloseP pcl; + pcl.level = restorestack(L, level); pcl.status = status; + status = luaD_rawrunprotected(L, &closepaux, &pcl); + if (likely(status == LUA_OK)) /* no more errors? */ + return pcl.status; + else { /* an error occurred; restore saved state and repeat */ + L->ci = old_ci; + L->allowhook = old_allowhooks; + } + } +} + + /* ** Call the C function 'func' in protected mode, restoring basic ** thread information ('allowhook', etc.) and in particular @@ -783,12 +842,10 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u, L->errfunc = ef; status = luaD_rawrunprotected(L, func, u); if (unlikely(status != LUA_OK)) { /* an error occurred? */ - StkId oldtop = restorestack(L, old_top); L->ci = old_ci; L->allowhook = old_allowhooks; - status = luaF_close(L, oldtop, status); - oldtop = restorestack(L, old_top); /* previous call may change stack */ - luaD_seterrorobj(L, status, oldtop); + status = luaD_closeprotected(L, old_top, status); + luaD_seterrorobj(L, status, restorestack(L, old_top)); luaD_shrinkstack(L); /* restore stack size in case of overflow */ } L->errfunc = old_errfunc; diff --git a/src/lua/ldo.h b/src/lua/ldo.h index 4d30d07..c7721d6 100644 --- a/src/lua/ldo.h +++ b/src/lua/ldo.h @@ -63,6 +63,7 @@ LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults); LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults); LUAI_FUNC void luaD_tryfuncTM (lua_State *L, StkId func); +LUAI_FUNC int luaD_closeprotected (lua_State *L, ptrdiff_t level, int status); LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, ptrdiff_t oldtop, ptrdiff_t ef); LUAI_FUNC void luaD_poscall (lua_State *L, CallInfo *ci, int nres); diff --git a/src/lua/lfunc.c b/src/lua/lfunc.c index c4360f0..13e44d4 100644 --- a/src/lua/lfunc.c +++ b/src/lua/lfunc.c @@ -100,80 +100,57 @@ UpVal *luaF_findupval (lua_State *L, StkId level) { } -static void callclose (lua_State *L, void *ud) { - UNUSED(ud); - luaD_callnoyield(L, L->top - 3, 0); -} - - /* -** Prepare closing method plus its arguments for object 'obj' with -** error message 'err'. (This function assumes EXTRA_STACK.) +** Call closing method for object 'obj' with error message 'err'. The +** boolean 'yy' controls whether the call is yieldable. +** (This function assumes EXTRA_STACK.) */ -static int prepclosingmethod (lua_State *L, TValue *obj, TValue *err) { +static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) { StkId top = L->top; const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE); - if (ttisnil(tm)) /* no metamethod? */ - return 0; /* nothing to call */ setobj2s(L, top, tm); /* will call metamethod... */ setobj2s(L, top + 1, obj); /* with 'self' as the 1st argument */ setobj2s(L, top + 2, err); /* and error msg. as 2nd argument */ L->top = top + 3; /* add function and arguments */ - return 1; + if (yy) + luaD_call(L, top, 0); + else + luaD_callnoyield(L, top, 0); } /* -** Raise an error with message 'msg', inserting the name of the -** local variable at position 'level' in the stack. +** Check whether 'obj' has a close metamethod and raise an error +** if not. */ -static void varerror (lua_State *L, StkId level, const char *msg) { - int idx = cast_int(level - L->ci->func); - const char *vname = luaG_findlocal(L, L->ci, idx, NULL); - if (vname == NULL) vname = "?"; - luaG_runerror(L, msg, vname); +static void checkclosemth (lua_State *L, StkId level, const TValue *obj) { + const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE); + if (ttisnil(tm)) { /* no metamethod? */ + int idx = cast_int(level - L->ci->func); /* variable index */ + const char *vname = luaG_findlocal(L, L->ci, idx, NULL); + if (vname == NULL) vname = "?"; + luaG_runerror(L, "variable '%s' got a non-closable value", vname); + } } /* -** Prepare and call a closing method. If status is OK, code is still -** inside the original protected call, and so any error will be handled -** there. Otherwise, a previous error already activated the original -** protected call, and so the call to the closing method must be -** protected here. (A status == CLOSEPROTECT behaves like a previous -** error, to also run the closing method in protected mode). -** If status is OK, the call to the closing method will be pushed -** at the top of the stack. Otherwise, values are pushed after -** the 'level' of the upvalue being closed, as everything after -** that won't be used again. +** Prepare and call a closing method. +** If status is CLOSEKTOP, the call to the closing method will be pushed +** at the top of the stack. Otherwise, values can be pushed right after +** the 'level' of the upvalue being closed, as everything after that +** won't be used again. */ -static int callclosemth (lua_State *L, StkId level, int status) { +static void prepcallclosemth (lua_State *L, StkId level, int status, int yy) { TValue *uv = s2v(level); /* value being closed */ - if (likely(status == LUA_OK)) { - if (prepclosingmethod(L, uv, &G(L)->nilvalue)) /* something to call? */ - callclose(L, NULL); /* call closing method */ - else if (!l_isfalse(uv)) /* non-closable non-false value? */ - varerror(L, level, "attempt to close non-closable variable '%s'"); + TValue *errobj; + if (status == CLOSEKTOP) + errobj = &G(L)->nilvalue; /* error object is nil */ + else { /* 'luaD_seterrorobj' will set top to level + 2 */ + errobj = s2v(level + 1); /* error object goes after 'uv' */ + luaD_seterrorobj(L, status, level + 1); /* set error object */ } - else { /* must close the object in protected mode */ - ptrdiff_t oldtop; - level++; /* space for error message */ - oldtop = savestack(L, level + 1); /* top will be after that */ - luaD_seterrorobj(L, status, level); /* set error message */ - if (prepclosingmethod(L, uv, s2v(level))) { /* something to call? */ - int newstatus = luaD_pcall(L, callclose, NULL, oldtop, 0); - if (newstatus != LUA_OK && status == CLOSEPROTECT) /* first error? */ - status = newstatus; /* this will be the new error */ - else { - if (newstatus != LUA_OK) /* suppressed error? */ - luaE_warnerror(L, "__close metamethod"); - /* leave original error (or nil) on top */ - L->top = restorestack(L, oldtop); - } - } - /* else no metamethod; ignore this case and keep original error */ - } - return status; + callclosemethod(L, uv, errobj, yy); } @@ -196,16 +173,12 @@ void luaF_newtbcupval (lua_State *L, StkId level) { lua_assert(L->openupval == NULL || uplevel(L->openupval) < level); if (!l_isfalse(obj)) { /* false doesn't need to be closed */ int status; - const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE); - if (ttisnil(tm)) /* no metamethod? */ - varerror(L, level, "variable '%s' got a non-closable value"); + checkclosemth(L, level, obj); status = luaD_rawrunprotected(L, trynewtbcupval, level); if (unlikely(status != LUA_OK)) { /* memory error creating upvalue? */ lua_assert(status == LUA_ERRMEM); luaD_seterrorobj(L, LUA_ERRMEM, level + 1); /* save error message */ - /* next call must succeed, as object is closable */ - prepclosingmethod(L, s2v(level), s2v(level + 1)); - callclose(L, NULL); /* call closing method */ + callclosemethod(L, s2v(level), s2v(level + 1), 0); luaD_throw(L, LUA_ERRMEM); /* throw memory error */ } } @@ -220,26 +193,30 @@ void luaF_unlinkupval (UpVal *uv) { } -int luaF_close (lua_State *L, StkId level, int status) { +/* +** Close all upvalues up to the given stack level. A 'status' equal +** to NOCLOSINGMETH closes upvalues without running any __close +** metamethods. +*/ +void luaF_close (lua_State *L, StkId level, int status, int yy) { UpVal *uv; - while ((uv = L->openupval) != NULL && uplevel(uv) >= level) { + StkId upl; /* stack index pointed by 'uv' */ + while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) { TValue *slot = &uv->u.value; /* new position for value */ lua_assert(uplevel(uv) < L->top); - if (uv->tbc && status != NOCLOSINGMETH) { - /* must run closing method, which may change the stack */ - ptrdiff_t levelrel = savestack(L, level); - status = callclosemth(L, uplevel(uv), status); - level = restorestack(L, levelrel); - } - luaF_unlinkupval(uv); + luaF_unlinkupval(uv); /* remove upvalue from 'openupval' list */ setobj(L, slot, uv->v); /* move value to upvalue slot */ uv->v = slot; /* now current value lives here */ if (!iswhite(uv)) { /* neither white nor dead? */ nw2black(uv); /* closed upvalues cannot be gray */ luaC_barrier(L, uv, slot); } + if (uv->tbc && status != NOCLOSINGMETH) { + ptrdiff_t levelrel = savestack(L, level); + prepcallclosemth(L, upl, status, yy); /* may change the stack */ + level = restorestack(L, levelrel); + } } - return status; } diff --git a/src/lua/lfunc.h b/src/lua/lfunc.h index 8d6f965..2e6df53 100644 --- a/src/lua/lfunc.h +++ b/src/lua/lfunc.h @@ -49,8 +49,8 @@ /* close upvalues without running their closing methods */ #define NOCLOSINGMETH (-1) -/* close upvalues running all closing methods in protected mode */ -#define CLOSEPROTECT (-2) +/* special status to close upvalues preserving the top of the stack */ +#define CLOSEKTOP (-2) LUAI_FUNC Proto *luaF_newproto (lua_State *L); @@ -59,7 +59,7 @@ LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nupvals); LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl); LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level); -LUAI_FUNC int luaF_close (lua_State *L, StkId level, int status); +LUAI_FUNC void luaF_close (lua_State *L, StkId level, int status, int yy); LUAI_FUNC void luaF_unlinkupval (UpVal *uv); LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, diff --git a/src/lua/lobject.h b/src/lua/lobject.h index 1cc8e75..470b17d 100644 --- a/src/lua/lobject.h +++ b/src/lua/lobject.h @@ -570,10 +570,11 @@ typedef struct Proto { #define LUA_VCCL makevariant(LUA_TFUNCTION, 2) /* C closure */ #define ttisfunction(o) checktype(o, LUA_TFUNCTION) -#define ttisclosure(o) ((rawtt(o) & 0x1F) == LUA_VLCL) #define ttisLclosure(o) checktag((o), ctb(LUA_VLCL)) #define ttislcf(o) checktag((o), LUA_VLCF) #define ttisCclosure(o) checktag((o), ctb(LUA_VCCL)) +#define ttisclosure(o) (ttisLclosure(o) || ttisCclosure(o)) + #define isLfunction(o) ttisLclosure(o) diff --git a/src/lua/lstate.c b/src/lua/lstate.c index 1596b51..92ccbf9 100644 --- a/src/lua/lstate.c +++ b/src/lua/lstate.c @@ -268,7 +268,7 @@ static void preinit_thread (lua_State *L, global_State *g) { static void close_state (lua_State *L) { global_State *g = G(L); - luaF_close(L, L->stack, CLOSEPROTECT); /* close all upvalues */ + luaD_closeprotected(L, 0, LUA_OK); /* close all upvalues */ luaC_freeallobjects(L); /* collect all objects */ if (ttisnil(&g->nilvalue)) /* closing a fully built state? */ luai_userstateclose(L); @@ -313,7 +313,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) { void luaE_freethread (lua_State *L, lua_State *L1) { LX *l = fromstate(L1); - luaF_close(L1, L1->stack, NOCLOSINGMETH); /* close all upvalues */ + luaF_close(L1, L1->stack, NOCLOSINGMETH, 0); /* close all upvalues */ lua_assert(L1->openupval == NULL); luai_userstatefree(L, L1); freestack(L1); @@ -321,23 +321,29 @@ void luaE_freethread (lua_State *L, lua_State *L1) { } -int lua_resetthread (lua_State *L) { - CallInfo *ci; - int status; - lua_lock(L); - L->ci = ci = &L->base_ci; /* unwind CallInfo list */ +int luaE_resetthread (lua_State *L, int status) { + CallInfo *ci = L->ci = &L->base_ci; /* unwind CallInfo list */ setnilvalue(s2v(L->stack)); /* 'function' entry for basic 'ci' */ ci->func = L->stack; ci->callstatus = CIST_C; - status = luaF_close(L, L->stack, CLOSEPROTECT); - if (status != CLOSEPROTECT) /* real errors? */ - luaD_seterrorobj(L, status, L->stack + 1); - else { + if (status == LUA_YIELD) status = LUA_OK; + status = luaD_closeprotected(L, 0, status); + if (status != LUA_OK) /* errors? */ + luaD_seterrorobj(L, status, L->stack + 1); + else L->top = L->stack + 1; - } ci->top = L->top + LUA_MINSTACK; - L->status = status; + L->status = cast_byte(status); + luaD_reallocstack(L, cast_int(ci->top - L->stack), 0); + return status; +} + + +LUA_API int lua_resetthread (lua_State *L) { + int status; + lua_lock(L); + status = luaE_resetthread(L, L->status); lua_unlock(L); return status; } diff --git a/src/lua/lstate.h b/src/lua/lstate.h index cbcf07e..38a6c9b 100644 --- a/src/lua/lstate.h +++ b/src/lua/lstate.h @@ -359,6 +359,7 @@ LUAI_FUNC void luaE_checkcstack (lua_State *L); LUAI_FUNC void luaE_incCstack (lua_State *L); LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont); LUAI_FUNC void luaE_warnerror (lua_State *L, const char *where); +LUAI_FUNC int luaE_resetthread (lua_State *L, int status); #endif diff --git a/src/lua/lstrlib.c b/src/lua/lstrlib.c index 940a14c..c7242ea 100644 --- a/src/lua/lstrlib.c +++ b/src/lua/lstrlib.c @@ -1358,16 +1358,6 @@ struct cD { #define MAXALIGN (offsetof(struct cD, u)) -/* -** Union for serializing floats -*/ -typedef union Ftypes { - float f; - double d; - lua_Number n; -} Ftypes; - - /* ** information to pack/unpack stuff */ @@ -1384,7 +1374,9 @@ typedef struct Header { typedef enum KOption { Kint, /* signed integers */ Kuint, /* unsigned integers */ - Kfloat, /* floating-point numbers */ + Kfloat, /* single-precision floating-point numbers */ + Knumber, /* Lua "native" floating-point numbers */ + Kdouble, /* double-precision floating-point numbers */ Kchar, /* fixed-length strings */ Kstring, /* strings with prefixed length */ Kzstr, /* zero-terminated strings */ @@ -1453,8 +1445,8 @@ static KOption getoption (Header *h, const char **fmt, int *size) { case 'J': *size = sizeof(lua_Integer); return Kuint; case 'T': *size = sizeof(size_t); return Kuint; case 'f': *size = sizeof(float); return Kfloat; - case 'd': *size = sizeof(double); return Kfloat; - case 'n': *size = sizeof(lua_Number); return Kfloat; + case 'n': *size = sizeof(lua_Number); return Knumber; + case 'd': *size = sizeof(double); return Kdouble; case 'i': *size = getnumlimit(h, fmt, sizeof(int)); return Kint; case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint; case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring; @@ -1580,15 +1572,27 @@ static int str_pack (lua_State *L) { packint(&b, (lua_Unsigned)n, h.islittle, size, 0); break; } - case Kfloat: { /* floating-point options */ - Ftypes u; - char *buff = luaL_prepbuffsize(&b, size); - lua_Number n = luaL_checknumber(L, arg); /* get argument */ - if (size == sizeof(u.f)) u.f = (float)n; /* copy it into 'u' */ - else if (size == sizeof(u.d)) u.d = (double)n; - else u.n = n; - /* move 'u' to final result, correcting endianness if needed */ - copywithendian(buff, (char *)&u, size, h.islittle); + case Kfloat: { /* C float */ + float f = (float)luaL_checknumber(L, arg); /* get argument */ + char *buff = luaL_prepbuffsize(&b, sizeof(f)); + /* move 'f' to final result, correcting endianness if needed */ + copywithendian(buff, (char *)&f, sizeof(f), h.islittle); + luaL_addsize(&b, size); + break; + } + case Knumber: { /* Lua float */ + lua_Number f = luaL_checknumber(L, arg); /* get argument */ + char *buff = luaL_prepbuffsize(&b, sizeof(f)); + /* move 'f' to final result, correcting endianness if needed */ + copywithendian(buff, (char *)&f, sizeof(f), h.islittle); + luaL_addsize(&b, size); + break; + } + case Kdouble: { /* C double */ + double f = (double)luaL_checknumber(L, arg); /* get argument */ + char *buff = luaL_prepbuffsize(&b, sizeof(f)); + /* move 'f' to final result, correcting endianness if needed */ + copywithendian(buff, (char *)&f, sizeof(f), h.islittle); luaL_addsize(&b, size); break; } @@ -1714,13 +1718,21 @@ static int str_unpack (lua_State *L) { break; } case Kfloat: { - Ftypes u; - lua_Number num; - copywithendian((char *)&u, data + pos, size, h.islittle); - if (size == sizeof(u.f)) num = (lua_Number)u.f; - else if (size == sizeof(u.d)) num = (lua_Number)u.d; - else num = u.n; - lua_pushnumber(L, num); + float f; + copywithendian((char *)&f, data + pos, sizeof(f), h.islittle); + lua_pushnumber(L, (lua_Number)f); + break; + } + case Knumber: { + lua_Number f; + copywithendian((char *)&f, data + pos, sizeof(f), h.islittle); + lua_pushnumber(L, f); + break; + } + case Kdouble: { + double f; + copywithendian((char *)&f, data + pos, sizeof(f), h.islittle); + lua_pushnumber(L, (lua_Number)f); break; } case Kchar: { diff --git a/src/lua/ltable.c b/src/lua/ltable.c index e9410f9..e98bab7 100644 --- a/src/lua/ltable.c +++ b/src/lua/ltable.c @@ -647,6 +647,8 @@ void luaH_newkey (lua_State *L, Table *t, const TValue *key, TValue *value) { else if (unlikely(luai_numisnan(f))) luaG_runerror(L, "table index is NaN"); } + if (ttisnil(value)) + return; /* do not insert nil values */ mp = mainpositionTV(t, key); if (!isempty(gval(mp)) || isdummy(t)) { /* main position is taken? */ Node *othern; diff --git a/src/lua/lua.h b/src/lua/lua.h index c9d64d7..aec70da 100644 --- a/src/lua/lua.h +++ b/src/lua/lua.h @@ -347,7 +347,8 @@ LUA_API size_t (lua_stringtonumber) (lua_State *L, const char *s); LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud); LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); -LUA_API void (lua_toclose) (lua_State *L, int idx); +LUA_API void (lua_toclose) (lua_State *L, int idx); +LUA_API void (lua_closeslot) (lua_State *L, int idx); /* diff --git a/src/lua/lvm.c b/src/lua/lvm.c index ccebdbe..d6c05bb 100644 --- a/src/lua/lvm.c +++ b/src/lua/lvm.c @@ -842,6 +842,10 @@ void luaV_finishOp (lua_State *L) { luaV_concat(L, total); /* concat them (may yield again) */ break; } + case OP_CLOSE: case OP_RETURN: { /* yielded closing variables */ + ci->u.l.savedpc--; /* repeat instruction to close other vars. */ + break; + } default: { /* only these other opcodes can yield */ lua_assert(op == OP_TFORCALL || op == OP_CALL || @@ -1524,7 +1528,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { vmbreak; } vmcase(OP_CLOSE) { - Protect(luaF_close(L, ra, LUA_OK)); + Protect(luaF_close(L, ra, LUA_OK, 1)); vmbreak; } vmcase(OP_TBC) { @@ -1632,7 +1636,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { /* close upvalues from current call; the compiler ensures that there are no to-be-closed variables here, so this call cannot change the stack */ - luaF_close(L, base, NOCLOSINGMETH); + luaF_close(L, base, NOCLOSINGMETH, 0); lua_assert(base == ci->func + 1); } while (!ttisfunction(s2v(ra))) { /* not a function? */ @@ -1662,7 +1666,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { if (TESTARG_k(i)) { /* may there be open upvalues? */ if (L->top < ci->top) L->top = ci->top; - luaF_close(L, base, LUA_OK); + luaF_close(L, base, CLOSEKTOP, 1); updatetrap(ci); updatestack(ci); } -- cgit v1.2.3-55-g6feb