From 8c596dc1efa8a1267c222b168a4de9c8ba254760 Mon Sep 17 00:00:00 2001 From: Li Jin Date: Sat, 18 Jul 2020 16:45:50 +0800 Subject: fix issue for using return statement with export. --- src/MoonP/moon_compiler.cpp | 30 ++++++++++++++++++++++++++- src/lua/lapi.c | 43 +++++++++++++++++++++++++-------------- src/lua/lauxlib.c | 6 ++++-- src/lua/lcorolib.c | 9 +++++---- src/lua/ldo.c | 23 +++++++++++---------- src/lua/ldo.h | 6 ++++-- src/lua/lgc.c | 10 ++++----- src/lua/liolib.c | 7 +++++++ src/lua/llimits.h | 10 ++++++++- src/lua/lmem.c | 2 +- src/lua/lobject.c | 49 +++++++++++++++++++++++++++------------------ src/lua/lstate.c | 6 ++++-- src/lua/ltm.c | 4 ++-- src/lua/lundump.c | 9 ++++++++- src/lua/lvm.c | 18 ++++++++--------- 15 files changed, 154 insertions(+), 78 deletions(-) (limited to 'src') diff --git a/src/MoonP/moon_compiler.cpp b/src/MoonP/moon_compiler.cpp index 41d29df..1d9161b 100644 --- a/src/MoonP/moon_compiler.cpp +++ b/src/MoonP/moon_compiler.cpp @@ -49,7 +49,7 @@ inline std::string s(std::string_view sv) { } const std::string_view version() { - return "0.4.4"sv; + return "0.4.5"sv; } // name of table stored in lua registry @@ -1498,6 +1498,7 @@ private: if (usage == ExpUsage::Closure) { temp.push_back(s("(function()"sv) + nll(nodes.front())); pushScope(); + _enableReturn.push(true); } std::list> ifCondPairs; ifCondPairs.emplace_back(); @@ -1613,6 +1614,7 @@ private: temp.push_back(indent() + s("end"sv) + nlr(nodes.front())); } if (usage == ExpUsage::Closure) { + _enableReturn.pop(); popScope(); temp.push_back(indent() + s("end)()"sv)); } @@ -2588,6 +2590,7 @@ private: if (usage == ExpUsage::Closure) { temp.push_back(s("(function()"sv) + nll(x)); pushScope(); + _enableReturn.push(true); } auto partOne = x->new_ptr(); for (auto it = chainList.begin();it != opIt;++it) { @@ -2718,6 +2721,7 @@ private: break; case ExpUsage::Closure: temp.push_back(indent() + s("return nil"sv) + nlr(x)); + _enableReturn.pop(); popScope(); temp.push_back(indent() + s("end)()"sv)); break; @@ -2742,6 +2746,7 @@ private: case ExpUsage::Closure: temp.push_back(s("(function()"sv) + nll(x)); pushScope(); + _enableReturn.push(true); break; default: break; @@ -2813,6 +2818,7 @@ private: temp.push_back(indent() + s("end"sv) + nlr(x)); break; case ExpUsage::Closure: + _enableReturn.pop(); popScope(); temp.push_back(indent() + s("end)()"sv)); break; @@ -3359,6 +3365,9 @@ private: auto x = comp; switch (usage) { case ExpUsage::Closure: + _enableReturn.push(true); + pushScope(); + break; case ExpUsage::Assignment: pushScope(); break; @@ -3413,6 +3422,7 @@ private: case ExpUsage::Common: break; case ExpUsage::Closure: { + _enableReturn.pop(); out.push_back(clearBuf()); out.back().append(indent() + s("return "sv) + accumVar + nlr(comp)); popScope(); @@ -3697,8 +3707,10 @@ private: str_list temp; _buf << "(function()"sv << nll(forNode); pushScope(); + _enableReturn.push(true); auto accum = transformForInner(forNode, temp); temp.push_back(indent() + s("return "sv) + accum + nlr(forNode)); + _enableReturn.pop(); popScope(); temp.push_back(indent() + s("end)()"sv)); out.push_back(join(temp)); @@ -3764,8 +3776,10 @@ private: str_list temp; _buf << "(function()"sv << nll(forEach); pushScope(); + _enableReturn.push(true); auto accum = transformForEachInner(forEach, temp); temp.push_back(indent() + s("return "sv) + accum + nlr(forEach)); + _enableReturn.pop(); popScope(); temp.push_back(indent() + s("end)()"sv)); out.push_back(join(temp)); @@ -3918,7 +3932,9 @@ private: str_list temp; temp.push_back(s("(function()"sv) + nll(classDecl)); pushScope(); + _enableReturn.push(true); transformClassDecl(classDecl, temp, ExpUsage::Return); + _enableReturn.pop(); popScope(); temp.push_back(s("end)()"sv)); out.push_back(join(temp)); @@ -4280,7 +4296,9 @@ private: str_list temp; temp.push_back(s("(function()"sv) + nll(with)); pushScope(); + _enableReturn.push(true); transformWith(with, temp, nullptr, true); + _enableReturn.pop(); popScope(); temp.push_back(indent() + s("end)()"sv)); out.push_back(join(temp)); @@ -4605,6 +4623,9 @@ private: void transformTblComprehension(TblComprehension_t* comp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { switch (usage) { case ExpUsage::Closure: + pushScope(); + _enableReturn.push(true); + break; case ExpUsage::Assignment: pushScope(); break; @@ -4660,6 +4681,7 @@ private: case ExpUsage::Closure: out.push_back(clearBuf() + indent() + s("return "sv) + tbl + nlr(comp)); popScope(); + _enableReturn.pop(); out.back().insert(0, s("(function()"sv) + nll(comp)); out.back().append(indent() + s("end)()"sv)); break; @@ -4713,6 +4735,7 @@ private: str_list temp; if (usage == ExpUsage::Closure) { temp.push_back(s("(function()"sv) + nll(doNode)); + _enableReturn.push(true); } else { temp.push_back(indent() + s("do"sv) + nll(doNode)); } @@ -4720,6 +4743,7 @@ private: transformBody(doNode->body, temp, usage, assignList); popScope(); if (usage == ExpUsage::Closure) { + _enableReturn.pop(); temp.push_back(indent() + s("end)()"sv)); } else { temp.push_back(indent() + s("end"sv) + nlr(doNode)); @@ -4990,6 +5014,7 @@ private: str_list temp; temp.push_back(s("(function() "sv) + nll(whileNode)); pushScope(); + _enableReturn.push(true); auto accumVar = getUnusedName("_accum_"sv); addToScope(accumVar); auto lenVar = getUnusedName("_len_"sv); @@ -5005,6 +5030,7 @@ private: popScope(); temp.push_back(indent() + s("end"sv) + nlr(whileNode)); temp.push_back(indent() + s("return "sv) + accumVar + nlr(whileNode)); + _enableReturn.pop(); popScope(); temp.push_back(indent() + s("end)()"sv)); out.push_back(join(temp)); @@ -5039,6 +5065,7 @@ private: if (usage == ExpUsage::Closure) { temp.push_back(s("(function()"sv) + nll(switchNode)); pushScope(); + _enableReturn.push(true); } auto objVar = singleVariableFrom(switchNode->target); if (objVar.empty()) { @@ -5076,6 +5103,7 @@ private: } temp.push_back(indent() + s("end"sv) + nlr(switchNode)); if (usage == ExpUsage::Closure) { + _enableReturn.pop(); popScope(); temp.push_back(indent() + s("end)()"sv)); } diff --git a/src/lua/lapi.c b/src/lua/lapi.c index 3e24781..9048245 100644 --- a/src/lua/lapi.c +++ b/src/lua/lapi.c @@ -97,8 +97,9 @@ static StkId index2stack (lua_State *L, int idx) { LUA_API int lua_checkstack (lua_State *L, int n) { int res; - CallInfo *ci = L->ci; + CallInfo *ci; lua_lock(L); + ci = L->ci; api_check(L, n >= 0, "negative 'n'"); if (L->stack_last - L->top > n) /* stack large enough? */ res = 1; /* yes; check is OK */ @@ -170,10 +171,12 @@ LUA_API int lua_gettop (lua_State *L) { LUA_API void lua_settop (lua_State *L, int idx) { - CallInfo *ci = L->ci; - StkId func = ci->func; + CallInfo *ci; + StkId func; ptrdiff_t diff; /* difference for new top */ lua_lock(L); + ci = L->ci; + func = ci->func; if (idx >= 0) { api_check(L, idx <= ci->top - (func + 1), "new top too large"); diff = ((func + 1) + idx) - L->top; @@ -376,20 +379,22 @@ LUA_API int lua_toboolean (lua_State *L, int idx) { LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) { - TValue *o = index2value(L, idx); + TValue *o; + lua_lock(L); + o = index2value(L, idx); if (!ttisstring(o)) { if (!cvt2str(o)) { /* not convertible? */ if (len != NULL) *len = 0; + lua_unlock(L); return NULL; } - lua_lock(L); /* 'luaO_tostring' may create a new string */ luaO_tostring(L, o); luaC_checkGC(L); o = index2value(L, idx); /* previous call may reallocate the stack */ - lua_unlock(L); } if (len != NULL) *len = vslen(o); + lua_unlock(L); return svalue(o); } @@ -563,6 +568,7 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { while (n--) { setobj2n(L, &cl->upvalue[n], s2v(L->top + n)); /* does not need barrier because closure is white */ + lua_assert(iswhite(cl)); } setclCvalue(L, s2v(L->top), cl); api_incr_top(L); @@ -624,8 +630,9 @@ static int auxgetstr (lua_State *L, const TValue *t, const char *k) { LUA_API int lua_getglobal (lua_State *L, const char *name) { - Table *reg = hvalue(&G(L)->l_registry); + Table *reg; lua_lock(L); + reg = hvalue(&G(L)->l_registry); return auxgetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name); } @@ -804,8 +811,9 @@ static void auxsetstr (lua_State *L, const TValue *t, const char *k) { LUA_API void lua_setglobal (lua_State *L, const char *name) { - Table *reg = hvalue(&G(L)->l_registry); + Table *reg; lua_lock(L); /* unlock done in 'auxsetstr' */ + reg = hvalue(&G(L)->l_registry); auxsetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name); } @@ -1093,8 +1101,9 @@ LUA_API int lua_status (lua_State *L) { LUA_API int lua_gc (lua_State *L, int what, ...) { va_list argp; int res = 0; - global_State *g = G(L); + global_State *g; lua_lock(L); + g = G(L); va_start(argp, what); switch (what) { case LUA_GCSTOP: { @@ -1194,9 +1203,15 @@ LUA_API int lua_gc (lua_State *L, int what, ...) { LUA_API int lua_error (lua_State *L) { + TValue *errobj; lua_lock(L); + errobj = s2v(L->top - 1); api_checknelems(L, 1); - luaG_errormsg(L); + /* error object is the memory error message? */ + if (ttisshrstring(errobj) && eqshrstr(tsvalue(errobj), G(L)->memerrmsg)) + luaM_error(L); /* raise a memory error */ + else + luaG_errormsg(L); /* raise a regular error */ /* code unreachable; will unlock when control actually leaves the kernel */ return 0; /* to avoid warnings */ } @@ -1238,14 +1253,12 @@ LUA_API void lua_toclose (lua_State *L, int idx) { LUA_API void lua_concat (lua_State *L, int n) { lua_lock(L); api_checknelems(L, n); - if (n >= 2) { + if (n > 0) luaV_concat(L, n); - } - else if (n == 0) { /* push empty string */ - setsvalue2s(L, L->top, luaS_newlstr(L, "", 0)); + else { /* nothing to concatenate */ + setsvalue2s(L, L->top, luaS_newlstr(L, "", 0)); /* push empty string */ api_incr_top(L); } - /* else n == 1; nothing to do */ luaC_checkGC(L); lua_unlock(L); } diff --git a/src/lua/lauxlib.c b/src/lua/lauxlib.c index e3d9be3..cbe9ed3 100644 --- a/src/lua/lauxlib.c +++ b/src/lua/lauxlib.c @@ -475,8 +475,10 @@ static void *resizebox (lua_State *L, int idx, size_t newsize) { lua_Alloc allocf = lua_getallocf(L, &ud); UBox *box = (UBox *)lua_touserdata(L, idx); void *temp = allocf(ud, box->box, box->bsize, newsize); - if (temp == NULL && newsize > 0) /* allocation error? */ - luaL_error(L, "not enough memory"); + if (temp == NULL && newsize > 0) { /* allocation error? */ + lua_pushliteral(L, "not enough memory"); + lua_error(L); /* raise a memory error */ + } box->box = temp; box->bsize = newsize; return temp; diff --git a/src/lua/lcorolib.c b/src/lua/lcorolib.c index 7d6e585..c165031 100644 --- a/src/lua/lcorolib.c +++ b/src/lua/lcorolib.c @@ -73,11 +73,12 @@ static int luaB_coresume (lua_State *L) { static int luaB_auxwrap (lua_State *L) { lua_State *co = lua_tothread(L, lua_upvalueindex(1)); int r = auxresume(L, co, lua_gettop(L)); - if (r < 0) { + if (r < 0) { /* error? */ int stat = lua_status(co); - if (stat != LUA_OK && stat != LUA_YIELD) - lua_resetthread(co); /* close variables in case of errors */ - if (lua_type(L, -1) == LUA_TSTRING) { /* error object is a string? */ + if (stat != LUA_OK && stat != LUA_YIELD) /* error in the coroutine? */ + lua_resetthread(co); /* close its tbc variables */ + 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 */ lua_insert(L, -2); lua_concat(L, 2); diff --git a/src/lua/ldo.c b/src/lua/ldo.c index c563b1d..4c976a1 100644 --- a/src/lua/ldo.c +++ b/src/lua/ldo.c @@ -245,13 +245,12 @@ static int stackinuse (lua_State *L) { void luaD_shrinkstack (lua_State *L) { int inuse = stackinuse(L); - int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK; + int goodsize = inuse + BASIC_STACK_SIZE; if (goodsize > LUAI_MAXSTACK) goodsize = LUAI_MAXSTACK; /* respect stack limit */ /* if thread is currently not handling a stack overflow and its good size is smaller than current size, shrink its stack */ - if (inuse <= (LUAI_MAXSTACK - EXTRA_STACK) && - goodsize < L->stacksize) + if (inuse <= (LUAI_MAXSTACK - EXTRA_STACK) && goodsize < L->stacksize) luaD_reallocstack(L, goodsize, 0); /* ok if that fails */ else /* don't change stack */ condmovestack(L,{},{}); /* (change only for debugging) */ @@ -466,13 +465,13 @@ void luaD_call (lua_State *L, StkId func, int nresults) { f = fvalue(s2v(func)); Cfunc: { int n; /* number of returns */ - CallInfo *ci = next_ci(L); - checkstackp(L, LUA_MINSTACK, func); /* ensure minimum stack size */ + CallInfo *ci; + checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */ + L->ci = ci = next_ci(L); ci->nresults = nresults; ci->callstatus = CIST_C; ci->top = L->top + LUA_MINSTACK; ci->func = func; - L->ci = ci; lua_assert(ci->top <= L->stack_last); if (L->hookmask & LUA_MASKCALL) { int narg = cast_int(L->top - func) - 1; @@ -486,12 +485,13 @@ void luaD_call (lua_State *L, StkId func, int nresults) { break; } case LUA_VLCL: { /* Lua function */ - CallInfo *ci = next_ci(L); + CallInfo *ci; Proto *p = clLvalue(s2v(func))->p; int narg = cast_int(L->top - func) - 1; /* number of real arguments */ int nfixparams = p->numparams; int fsize = p->maxstacksize; /* frame size */ - checkstackp(L, fsize, func); + checkstackGCp(L, fsize, func); + L->ci = ci = next_ci(L); ci->nresults = nresults; ci->u.l.savedpc = p->code; /* starting point */ ci->callstatus = 0; @@ -505,7 +505,7 @@ void luaD_call (lua_State *L, StkId func, int nresults) { break; } default: { /* not a function */ - checkstackp(L, 1, func); /* space for metamethod */ + checkstackGCp(L, 1, func); /* space for metamethod */ luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */ goto retry; /* try again with metamethod */ } @@ -674,7 +674,7 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs, if (from == NULL) L->nCcalls = CSTACKTHREAD; else /* correct 'nCcalls' for this thread */ - L->nCcalls = getCcalls(from) + from->nci - L->nci - CSTACKCF; + L->nCcalls = getCcalls(from) - L->nci - CSTACKCF; if (L->nCcalls <= CSTACKERR) return resume_error(L, "C stack overflow", nargs); luai_userstateresume(L, nargs); @@ -706,9 +706,10 @@ LUA_API int lua_isyieldable (lua_State *L) { LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx, lua_KFunction k) { - CallInfo *ci = L->ci; + CallInfo *ci; luai_userstateyield(L, nresults); lua_lock(L); + ci = L->ci; api_checknelems(L, nresults); if (unlikely(!yieldable(L))) { if (L != G(L)->mainthread) diff --git a/src/lua/ldo.h b/src/lua/ldo.h index 7760f85..6c6cb28 100644 --- a/src/lua/ldo.h +++ b/src/lua/ldo.h @@ -17,6 +17,8 @@ ** Macro to check stack size and grow stack if needed. Parameters ** 'pre'/'pos' allow the macro to preserve a pointer into the ** stack across reallocations, doing the work only when needed. +** It also allows the running of one GC step when the stack is +** reallocated. ** 'condmovestack' is used in heavy tests to force a stack reallocation ** at every check. */ @@ -35,7 +37,7 @@ /* macro to check stack size, preserving 'p' */ -#define checkstackp(L,n,p) \ +#define checkstackGCp(L,n,p) \ luaD_checkstackaux(L, n, \ ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \ luaC_checkGC(L), /* stack grow uses memory */ \ @@ -44,7 +46,7 @@ /* macro to check stack size and GC */ #define checkstackGC(L,fsize) \ - luaD_checkstackaux(L, (fsize), (void)0, luaC_checkGC(L)) + luaD_checkstackaux(L, (fsize), luaC_checkGC(L), (void)0) /* type of protected functions, to be ran by 'runprotected' */ diff --git a/src/lua/lgc.c b/src/lua/lgc.c index f26c921..f7fd7a5 100644 --- a/src/lua/lgc.c +++ b/src/lua/lgc.c @@ -1131,16 +1131,14 @@ static void finishgencycle (lua_State *L, global_State *g) { /* -** Does a young collection. First, mark 'OLD1' objects. (Only survival -** and "recent old" lists can contain 'OLD1' objects. New lists cannot -** contain 'OLD1' objects, at most 'OLD0' objects that were already -** visited when marked old.) Then does the atomic step. Then, -** sweep all lists and advance pointers. Finally, finish the collection. +** Does a young collection. First, mark 'OLD1' objects. Then does the +** atomic step. Then, sweep all lists and advance pointers. Finally, +** finish the collection. */ static void youngcollection (lua_State *L, global_State *g) { GCObject **psurvival; /* to point to first non-dead survival object */ lua_assert(g->gcstate == GCSpropagate); - markold(g, g->survival, g->reallyold); + markold(g, g->allgc, g->reallyold); markold(g, g->finobj, g->finobjrold); atomic(L); diff --git a/src/lua/liolib.c b/src/lua/liolib.c index 7ac3444..60ab1bf 100644 --- a/src/lua/liolib.c +++ b/src/lua/liolib.c @@ -52,6 +52,12 @@ static int l_checkmode (const char *mode) { ** ======================================================= */ +#if !defined(l_checkmodep) +/* By default, Lua accepts only "r" or "w" as mode */ +#define l_checkmodep(m) ((m[0] == 'r' || m[0] == 'w') && m[1] == '\0') +#endif + + #if !defined(l_popen) /* { */ #if defined(LUA_USE_POSIX) /* { */ @@ -279,6 +285,7 @@ static int io_popen (lua_State *L) { const char *filename = luaL_checkstring(L, 1); const char *mode = luaL_optstring(L, 2, "r"); LStream *p = newprefile(L); + luaL_argcheck(L, l_checkmodep(mode), 2, "invalid mode"); p->f = l_popen(L, filename, mode); p->closef = &io_pclose; return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; diff --git a/src/lua/llimits.h b/src/lua/llimits.h index b86d345..48c97f9 100644 --- a/src/lua/llimits.h +++ b/src/lua/llimits.h @@ -84,7 +84,15 @@ typedef LUAI_UACNUMBER l_uacNumber; typedef LUAI_UACINT l_uacInt; -/* internal assertions for in-house debugging */ +/* +** Internal assertions for in-house debugging +*/ +#if defined LUAI_ASSERT +#undef NDEBUG +#include +#define lua_assert(c) assert(c) +#endif + #if defined(lua_assert) #define check_exp(c,e) (lua_assert(c), (e)) /* to avoid problems with conditions too long */ diff --git a/src/lua/lmem.c b/src/lua/lmem.c index 65bfa52..43739bf 100644 --- a/src/lua/lmem.c +++ b/src/lua/lmem.c @@ -22,7 +22,7 @@ #include "lstate.h" -#if defined(HARDMEMTESTS) +#if defined(EMERGENCYGCTESTS) /* ** First allocation will fail whenever not building initial state ** and not shrinking a block. (This fail will trigger 'tryagain' and diff --git a/src/lua/lobject.c b/src/lua/lobject.c index b4efae4..f8ea917 100644 --- a/src/lua/lobject.c +++ b/src/lua/lobject.c @@ -215,37 +215,42 @@ static lua_Number lua_strx2number (const char *s, char **endptr) { /* }====================================================== */ -/* maximum length of a numeral */ +/* maximum length of a numeral to be converted to a number */ #if !defined (L_MAXLENNUM) #define L_MAXLENNUM 200 #endif +/* +** Convert string 's' to a Lua number (put in 'result'). Return NULL on +** fail or the address of the ending '\0' on success. ('mode' == 'x') +** means a hexadecimal numeral. +*/ static const char *l_str2dloc (const char *s, lua_Number *result, int mode) { char *endptr; *result = (mode == 'x') ? lua_strx2number(s, &endptr) /* try to convert */ : lua_str2number(s, &endptr); if (endptr == s) return NULL; /* nothing recognized? */ while (lisspace(cast_uchar(*endptr))) endptr++; /* skip trailing spaces */ - return (*endptr == '\0') ? endptr : NULL; /* OK if no trailing characters */ + return (*endptr == '\0') ? endptr : NULL; /* OK iff no trailing chars */ } /* -** Convert string 's' to a Lua number (put in 'result'). Return NULL -** on fail or the address of the ending '\0' on success. -** 'pmode' points to (and 'mode' contains) special things in the string: -** - 'x'/'X' means a hexadecimal numeral -** - 'n'/'N' means 'inf' or 'nan' (which should be rejected) -** - '.' just optimizes the search for the common case (nothing special) +** Convert string 's' to a Lua number (put in 'result') handling the +** current locale. ** This function accepts both the current locale or a dot as the radix ** mark. If the conversion fails, it may mean number has a dot but ** locale accepts something else. In that case, the code copies 's' ** to a buffer (because 's' is read-only), changes the dot to the ** current locale radix mark, and tries to convert again. +** The variable 'mode' checks for special characters in the string: +** - 'n' means 'inf' or 'nan' (which should be rejected) +** - 'x' means a hexadecimal numeral +** - '.' just optimizes the search for the common case (no special chars) */ static const char *l_str2d (const char *s, lua_Number *result) { const char *endptr; - const char *pmode = strpbrk(s, ".xXnN"); + const char *pmode = strpbrk(s, ".xXnN"); /* look for special chars */ int mode = pmode ? ltolower(cast_uchar(*pmode)) : 0; if (mode == 'n') /* reject 'inf' and 'nan' */ return NULL; @@ -333,8 +338,15 @@ int luaO_utf8esc (char *buff, unsigned long x) { } -/* maximum length of the conversion of a number to a string */ -#define MAXNUMBER2STR 50 +/* +** Maximum length of the conversion of a number to a string. Must be +** enough to accommodate both LUA_INTEGER_FMT and LUA_NUMBER_FMT. +** (For a long long int, this is 19 digits plus a sign and a final '\0', +** adding to 21. For a long double, it can go to a sign, 33 digits, +** the dot, an exponent letter, an exponent sign, 5 exponent digits, +** and a final '\0', adding to 43.) +*/ +#define MAXNUMBER2STR 44 /* @@ -375,7 +387,7 @@ void luaO_tostring (lua_State *L, TValue *obj) { */ /* size for buffer space used by 'luaO_pushvfstring' */ -#define BUFVFS 400 +#define BUFVFS 200 /* buffer used by 'luaO_pushvfstring' */ typedef struct BuffFS { @@ -387,18 +399,16 @@ typedef struct BuffFS { /* -** Push given string to the stack, as part of the buffer. If the stack -** is almost full, join all partial strings in the stack into one. +** Push given string to the stack, as part of the buffer, and +** join the partial strings in the stack into one. */ static void pushstr (BuffFS *buff, const char *str, size_t l) { lua_State *L = buff->L; setsvalue2s(L, L->top, luaS_newlstr(L, str, l)); L->top++; /* may use one extra slot */ buff->pushed++; - if (buff->pushed > 1 && L->top + 1 >= L->stack_last) { - luaV_concat(L, buff->pushed); /* join all partial results into one */ - buff->pushed = 1; - } + luaV_concat(L, buff->pushed); /* join partial results into one */ + buff->pushed = 1; } @@ -521,8 +531,7 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { } addstr2buff(&buff, fmt, strlen(fmt)); /* rest of 'fmt' */ clearbuff(&buff); /* empty buffer into the stack */ - if (buff.pushed > 1) - luaV_concat(L, buff.pushed); /* join all partial results */ + lua_assert(buff.pushed == 1); return svalue(s2v(L->top - 1)); } diff --git a/src/lua/lstate.c b/src/lua/lstate.c index 4434211..28853dc 100644 --- a/src/lua/lstate.c +++ b/src/lua/lstate.c @@ -318,9 +318,10 @@ static void close_state (lua_State *L) { LUA_API lua_State *lua_newthread (lua_State *L) { - global_State *g = G(L); + global_State *g; lua_State *L1; lua_lock(L); + g = G(L); luaC_checkGC(L); /* create new thread */ L1 = &cast(LX *, luaM_newobject(L, LUA_TTHREAD, sizeof(LX)))->l; @@ -395,6 +396,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { g->allgc = obj2gco(L); /* by now, only object is the main thread */ L->next = NULL; g->Cstacklimit = L->nCcalls = LUAI_MAXCSTACK + CSTACKERR; + incnny(L); /* main thread is always non yieldable */ g->frealloc = f; g->ud = ud; g->warnf = NULL; @@ -436,8 +438,8 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { LUA_API void lua_close (lua_State *L) { - L = G(L)->mainthread; /* only the main thread can be closed */ lua_lock(L); + L = G(L)->mainthread; /* only the main thread can be closed */ close_state(L); } diff --git a/src/lua/ltm.c b/src/lua/ltm.c index ae60983..4770f96 100644 --- a/src/lua/ltm.c +++ b/src/lua/ltm.c @@ -240,7 +240,7 @@ void luaT_adjustvarargs (lua_State *L, int nfixparams, CallInfo *ci, int actual = cast_int(L->top - ci->func) - 1; /* number of arguments */ int nextra = actual - nfixparams; /* number of extra arguments */ ci->u.l.nextraargs = nextra; - checkstackGC(L, p->maxstacksize + 1); + luaD_checkstack(L, p->maxstacksize + 1); /* copy function to the top of the stack */ setobjs2s(L, L->top++, ci->func); /* move fixed parameters to the top of the stack */ @@ -259,7 +259,7 @@ void luaT_getvarargs (lua_State *L, CallInfo *ci, StkId where, int wanted) { int nextra = ci->u.l.nextraargs; if (wanted < 0) { wanted = nextra; /* get all extra arguments available */ - checkstackp(L, nextra, where); /* ensure stack space */ + checkstackGCp(L, nextra, where); /* ensure stack space */ L->top = where + nextra; /* next instruction will need top */ } for (i = 0; i < wanted && i < nextra; i++) diff --git a/src/lua/lundump.c b/src/lua/lundump.c index 4243678..cb124d6 100644 --- a/src/lua/lundump.c +++ b/src/lua/lundump.c @@ -200,13 +200,20 @@ static void loadProtos (LoadState *S, Proto *f) { } +/* +** Load the upvalues for a function. The names must be filled first, +** because the filling of the other fields can raise read errors and +** the creation of the error message can call an emergency collection; +** in that case all prototypes must be consistent for the GC. +*/ static void loadUpvalues (LoadState *S, Proto *f) { int i, n; n = loadInt(S); f->upvalues = luaM_newvectorchecked(S->L, n, Upvaldesc); f->sizeupvalues = n; - for (i = 0; i < n; i++) { + for (i = 0; i < n; i++) /* make array valid for GC */ f->upvalues[i].name = NULL; + for (i = 0; i < n; i++) { /* following calls can raise errors */ f->upvalues[i].instack = loadByte(S); f->upvalues[i].idx = loadByte(S); f->upvalues[i].kind = loadByte(S); diff --git a/src/lua/lvm.c b/src/lua/lvm.c index e7781db..66d451b 100644 --- a/src/lua/lvm.c +++ b/src/lua/lvm.c @@ -634,7 +634,8 @@ static void copy2buff (StkId top, int n, char *buff) { ** from 'L->top - total' up to 'L->top - 1'. */ void luaV_concat (lua_State *L, int total) { - lua_assert(total >= 2); + if (total == 1) + return; /* "all" values already concatenated */ do { StkId top = L->top; int n = 2; /* number of elements handled in this pass (at least 2) */ @@ -840,10 +841,8 @@ void luaV_finishOp (lua_State *L) { int a = GETARG_A(inst); /* first element to concatenate */ int total = cast_int(top - 1 - (base + a)); /* yet to concatenate */ setobjs2s(L, top - 2, top); /* put TM result in proper position */ - if (total > 1) { /* are there elements to concat? */ - L->top = top - 1; /* top is one after last element (at top-2) */ - luaV_concat(L, total); /* concat them (may yield again) */ - } + L->top = top - 1; /* top is one after last element (at top-2) */ + luaV_concat(L, total); /* concat them (may yield again) */ break; } default: { @@ -1102,9 +1101,9 @@ void luaV_finishOp (lua_State *L) { /* idem, but without changing the stack */ #define halfProtectNT(exp) (savepc(L), (exp)) - +/* 'c' is the limit of live values in the stack */ #define checkGC(L,c) \ - { luaC_condGC(L, L->top = (c), /* limit of live values */ \ + { luaC_condGC(L, (savepc(L), L->top = (c)), \ updatetrap(ci)); \ luai_threadyield(L); } @@ -1635,7 +1634,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { while (!ttisfunction(s2v(ra))) { /* not a function? */ luaD_tryfuncTM(L, ra); /* try '__call' metamethod */ b++; /* there is now one extra argument */ - checkstackp(L, 1, ra); + checkstackGCp(L, 1, ra); } if (!ttisLclosure(s2v(ra))) { /* C function? */ luaD_call(L, ra, LUA_MULTRET); /* call it */ @@ -1792,8 +1791,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { vmbreak; } vmcase(OP_VARARGPREP) { - luaT_adjustvarargs(L, GETARG_A(i), ci, cl->p); - updatetrap(ci); + ProtectNT(luaT_adjustvarargs(L, GETARG_A(i), ci, cl->p)); if (trap) { luaD_hookcall(L, ci); L->oldpc = pc + 1; /* next opcode will be seen as a "new" line */ -- cgit v1.2.3-55-g6feb