Back to a stackless implementation
A "with stack" implementation gains too little in performance to be worth all the noise from C-stack overflows. This commit is almost a sketch, to test performance. There are several pending stuff: - review control of C-stack overflow and error messages; - what to do with setcstacklimit; - review comments; - review unroll of Lua calls.
This commit is contained in:
51
ldo.c
51
ldo.c
@@ -139,8 +139,7 @@ l_noret luaD_throw (lua_State *L, int errcode) {
|
|||||||
|
|
||||||
|
|
||||||
int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
|
int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
|
||||||
global_State *g = G(L);
|
l_uint32 oldnCcalls = L->nCcalls;
|
||||||
l_uint32 oldnCcalls = g->Cstacklimit - (L->nCcalls + L->nci);
|
|
||||||
struct lua_longjmp lj;
|
struct lua_longjmp lj;
|
||||||
lj.status = LUA_OK;
|
lj.status = LUA_OK;
|
||||||
lj.previous = L->errorJmp; /* chain new error handler */
|
lj.previous = L->errorJmp; /* chain new error handler */
|
||||||
@@ -149,7 +148,7 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
|
|||||||
(*f)(L, ud);
|
(*f)(L, ud);
|
||||||
);
|
);
|
||||||
L->errorJmp = lj.previous; /* restore old error handler */
|
L->errorJmp = lj.previous; /* restore old error handler */
|
||||||
L->nCcalls = g->Cstacklimit - oldnCcalls - L->nci;
|
L->nCcalls = oldnCcalls;
|
||||||
return lj.status;
|
return lj.status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -348,7 +347,7 @@ static StkId rethook (lua_State *L, CallInfo *ci, StkId firstres, int nres) {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** Check whether 'func' has a '__call' metafield. If so, put it in the
|
** Check whether 'func' has a '__call' metafield. If so, put it in the
|
||||||
** stack, below original 'func', so that 'luaD_call' can call it. Raise
|
** stack, below original 'func', so that 'luaD_precall' can call it. Raise
|
||||||
** an error if there is no '__call' metafield.
|
** an error if there is no '__call' metafield.
|
||||||
*/
|
*/
|
||||||
void luaD_tryfuncTM (lua_State *L, StkId func) {
|
void luaD_tryfuncTM (lua_State *L, StkId func) {
|
||||||
@@ -454,7 +453,7 @@ void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1) {
|
|||||||
** When returns, all the results are on the stack, starting at the original
|
** When returns, all the results are on the stack, starting at the original
|
||||||
** function position.
|
** function position.
|
||||||
*/
|
*/
|
||||||
void luaD_call (lua_State *L, StkId func, int nresults) {
|
int luaD_precall (lua_State *L, StkId func, int nresults) {
|
||||||
lua_CFunction f;
|
lua_CFunction f;
|
||||||
retry:
|
retry:
|
||||||
switch (ttypetag(s2v(func))) {
|
switch (ttypetag(s2v(func))) {
|
||||||
@@ -482,7 +481,7 @@ void luaD_call (lua_State *L, StkId func, int nresults) {
|
|||||||
lua_lock(L);
|
lua_lock(L);
|
||||||
api_checknelems(L, n);
|
api_checknelems(L, n);
|
||||||
luaD_poscall(L, ci, n);
|
luaD_poscall(L, ci, n);
|
||||||
break;
|
return 1;
|
||||||
}
|
}
|
||||||
case LUA_VLCL: { /* Lua function */
|
case LUA_VLCL: { /* Lua function */
|
||||||
CallInfo *ci;
|
CallInfo *ci;
|
||||||
@@ -501,8 +500,7 @@ void luaD_call (lua_State *L, StkId func, int nresults) {
|
|||||||
for (; narg < nfixparams; narg++)
|
for (; narg < nfixparams; narg++)
|
||||||
setnilvalue(s2v(L->top++)); /* complete missing arguments */
|
setnilvalue(s2v(L->top++)); /* complete missing arguments */
|
||||||
lua_assert(ci->top <= L->stack_last);
|
lua_assert(ci->top <= L->stack_last);
|
||||||
luaV_execute(L, ci); /* run the function */
|
return 0;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
default: { /* not a function */
|
default: { /* not a function */
|
||||||
checkstackGCp(L, 1, func); /* space for metamethod */
|
checkstackGCp(L, 1, func); /* space for metamethod */
|
||||||
@@ -513,17 +511,32 @@ void luaD_call (lua_State *L, StkId func, int nresults) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void stackerror (lua_State *L) {
|
||||||
|
if (getCcalls(L) == LUAI_MAXCCALLS)
|
||||||
|
luaG_runerror(L, "C stack overflow");
|
||||||
|
else if (getCcalls(L) >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3)))
|
||||||
|
luaD_throw(L, LUA_ERRERR); /* error while handing stack error */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void luaD_call (lua_State *L, StkId func, int nResults) {
|
||||||
|
L->nCcalls++;
|
||||||
|
if (getCcalls(L) >= LUAI_MAXCCALLS)
|
||||||
|
stackerror(L);
|
||||||
|
if (!luaD_precall(L, func, nResults)) /* is a Lua function? */
|
||||||
|
luaV_execute(L, L->ci); /* call it */
|
||||||
|
L->nCcalls--;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Similar to 'luaD_call', but does not allow yields during the call.
|
** Similar to 'luaD_call', but does not allow yields during the call.
|
||||||
*/
|
*/
|
||||||
void luaD_callnoyield (lua_State *L, StkId func, int nResults) {
|
void luaD_callnoyield (lua_State *L, StkId func, int nResults) {
|
||||||
incXCcalls(L);
|
incnny(L);
|
||||||
if (getCcalls(L) <= CSTACKERR) { /* possible C stack overflow? */
|
|
||||||
luaE_exitCcall(L); /* to compensate decrement in next call */
|
|
||||||
luaE_enterCcall(L); /* check properly */
|
|
||||||
}
|
|
||||||
luaD_call(L, func, nResults);
|
luaD_call(L, func, nResults);
|
||||||
decXCcalls(L);
|
decnny(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -638,7 +651,8 @@ static void resume (lua_State *L, void *ud) {
|
|||||||
StkId firstArg = L->top - n; /* first argument */
|
StkId firstArg = L->top - n; /* first argument */
|
||||||
CallInfo *ci = L->ci;
|
CallInfo *ci = L->ci;
|
||||||
if (L->status == LUA_OK) { /* starting a coroutine? */
|
if (L->status == LUA_OK) { /* starting a coroutine? */
|
||||||
luaD_call(L, firstArg - 1, LUA_MULTRET);
|
if (!luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* Lua function? */
|
||||||
|
luaV_execute(L, L->ci); /* call it */
|
||||||
}
|
}
|
||||||
else { /* resuming from previous yield */
|
else { /* resuming from previous yield */
|
||||||
lua_assert(L->status == LUA_YIELD);
|
lua_assert(L->status == LUA_YIELD);
|
||||||
@@ -670,11 +684,8 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
|
|||||||
}
|
}
|
||||||
else if (L->status != LUA_YIELD) /* ended with errors? */
|
else if (L->status != LUA_YIELD) /* ended with errors? */
|
||||||
return resume_error(L, "cannot resume dead coroutine", nargs);
|
return resume_error(L, "cannot resume dead coroutine", nargs);
|
||||||
if (from == NULL)
|
L->nCcalls = (from) ? getCcalls(from) + 1 : 1;
|
||||||
L->nCcalls = CSTACKTHREAD;
|
if (getCcalls(L) >= LUAI_MAXCCALLS)
|
||||||
else /* correct 'nCcalls' for this thread */
|
|
||||||
L->nCcalls = getCcalls(from) - L->nci - CSTACKCF;
|
|
||||||
if (L->nCcalls <= CSTACKERR)
|
|
||||||
return resume_error(L, "C stack overflow", nargs);
|
return resume_error(L, "C stack overflow", nargs);
|
||||||
luai_userstateresume(L, nargs);
|
luai_userstateresume(L, nargs);
|
||||||
api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs);
|
api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs);
|
||||||
|
|||||||
1
ldo.h
1
ldo.h
@@ -59,6 +59,7 @@ LUAI_FUNC void luaD_hook (lua_State *L, int event, int line,
|
|||||||
int fTransfer, int nTransfer);
|
int fTransfer, int nTransfer);
|
||||||
LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci);
|
LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci);
|
||||||
LUAI_FUNC void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int n);
|
LUAI_FUNC void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int n);
|
||||||
|
LUAI_FUNC int 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_call (lua_State *L, StkId func, int nResults);
|
||||||
LUAI_FUNC void luaD_callnoyield (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 void luaD_tryfuncTM (lua_State *L, StkId func);
|
||||||
|
|||||||
12
lparser.c
12
lparser.c
@@ -489,12 +489,14 @@ static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
static void enterlevel (LexState *ls) {
|
||||||
** Macros to limit the maximum recursion depth while parsing
|
lua_State *L = ls->L;
|
||||||
*/
|
L->nCcalls++;
|
||||||
#define enterlevel(ls) luaE_enterCcall((ls)->L)
|
checklimit(ls->fs, getCcalls(L), LUAI_MAXCCALLS, "C levels");
|
||||||
|
}
|
||||||
|
|
||||||
#define leavelevel(ls) luaE_exitCcall((ls)->L)
|
|
||||||
|
#define leavelevel(ls) ((ls)->L->nCcalls--)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
43
lstate.c
43
lstate.c
@@ -119,44 +119,9 @@ LUA_API int lua_setcstacklimit (lua_State *L, unsigned int limit) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Decrement count of "C calls" and check for overflows. In case of
|
|
||||||
** a stack overflow, check appropriate error ("regular" overflow or
|
|
||||||
** overflow while handling stack overflow). If 'nCcalls' is smaller
|
|
||||||
** than CSTACKERR but larger than CSTACKMARK, it means it has just
|
|
||||||
** entered the "overflow zone", so the function raises an overflow
|
|
||||||
** error. If 'nCcalls' is smaller than CSTACKMARK (which means it is
|
|
||||||
** already handling an overflow) but larger than CSTACKERRMARK, does
|
|
||||||
** not report an error (to allow message handling to work). Otherwise,
|
|
||||||
** report a stack overflow while handling a stack overflow (probably
|
|
||||||
** caused by a repeating error in the message handling function).
|
|
||||||
*/
|
|
||||||
|
|
||||||
void luaE_enterCcall (lua_State *L) {
|
|
||||||
int ncalls = getCcalls(L);
|
|
||||||
L->nCcalls--;
|
|
||||||
if (ncalls <= CSTACKERR) { /* possible overflow? */
|
|
||||||
luaE_freeCI(L); /* release unused CIs */
|
|
||||||
ncalls = getCcalls(L); /* update call count */
|
|
||||||
if (ncalls <= CSTACKERR) { /* still overflow? */
|
|
||||||
if (ncalls <= CSTACKERRMARK) /* below error-handling zone? */
|
|
||||||
luaD_throw(L, LUA_ERRERR); /* error while handling stack error */
|
|
||||||
else if (ncalls >= CSTACKMARK) {
|
|
||||||
/* not in error-handling zone; raise the error now */
|
|
||||||
L->nCcalls = (CSTACKMARK - 1); /* enter error-handling zone */
|
|
||||||
luaG_runerror(L, "C stack overflow");
|
|
||||||
}
|
|
||||||
/* else stack is in the error-handling zone;
|
|
||||||
allow message handler to work */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
CallInfo *luaE_extendCI (lua_State *L) {
|
CallInfo *luaE_extendCI (lua_State *L) {
|
||||||
CallInfo *ci;
|
CallInfo *ci;
|
||||||
lua_assert(L->ci->next == NULL);
|
lua_assert(L->ci->next == NULL);
|
||||||
luaE_enterCcall(L);
|
|
||||||
ci = luaM_new(L, CallInfo);
|
ci = luaM_new(L, CallInfo);
|
||||||
lua_assert(L->ci->next == NULL);
|
lua_assert(L->ci->next == NULL);
|
||||||
L->ci->next = ci;
|
L->ci->next = ci;
|
||||||
@@ -175,13 +140,11 @@ void luaE_freeCI (lua_State *L) {
|
|||||||
CallInfo *ci = L->ci;
|
CallInfo *ci = L->ci;
|
||||||
CallInfo *next = ci->next;
|
CallInfo *next = ci->next;
|
||||||
ci->next = NULL;
|
ci->next = NULL;
|
||||||
L->nCcalls += L->nci; /* add removed elements back to 'nCcalls' */
|
|
||||||
while ((ci = next) != NULL) {
|
while ((ci = next) != NULL) {
|
||||||
next = ci->next;
|
next = ci->next;
|
||||||
luaM_free(L, ci);
|
luaM_free(L, ci);
|
||||||
L->nci--;
|
L->nci--;
|
||||||
}
|
}
|
||||||
L->nCcalls -= L->nci; /* adjust result */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -194,7 +157,6 @@ void luaE_shrinkCI (lua_State *L) {
|
|||||||
CallInfo *next;
|
CallInfo *next;
|
||||||
if (ci == NULL)
|
if (ci == NULL)
|
||||||
return; /* no extra elements */
|
return; /* no extra elements */
|
||||||
L->nCcalls += L->nci; /* add removed elements back to 'nCcalls' */
|
|
||||||
while ((next = ci->next) != NULL) { /* two extra elements? */
|
while ((next = ci->next) != NULL) { /* two extra elements? */
|
||||||
CallInfo *next2 = next->next; /* next's next */
|
CallInfo *next2 = next->next; /* next's next */
|
||||||
ci->next = next2; /* remove next from the list */
|
ci->next = next2; /* remove next from the list */
|
||||||
@@ -207,7 +169,6 @@ void luaE_shrinkCI (lua_State *L) {
|
|||||||
ci = next2; /* continue */
|
ci = next2; /* continue */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
L->nCcalls -= L->nci; /* adjust result */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -335,7 +296,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) {
|
|||||||
setthvalue2s(L, L->top, L1);
|
setthvalue2s(L, L->top, L1);
|
||||||
api_incr_top(L);
|
api_incr_top(L);
|
||||||
preinit_thread(L1, g);
|
preinit_thread(L1, g);
|
||||||
L1->nCcalls = getCcalls(L);
|
L1->nCcalls = 0;
|
||||||
L1->hookmask = L->hookmask;
|
L1->hookmask = L->hookmask;
|
||||||
L1->basehookcount = L->basehookcount;
|
L1->basehookcount = L->basehookcount;
|
||||||
L1->hook = L->hook;
|
L1->hook = L->hook;
|
||||||
@@ -396,7 +357,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
|
|||||||
preinit_thread(L, g);
|
preinit_thread(L, g);
|
||||||
g->allgc = obj2gco(L); /* by now, only object is the main thread */
|
g->allgc = obj2gco(L); /* by now, only object is the main thread */
|
||||||
L->next = NULL;
|
L->next = NULL;
|
||||||
g->Cstacklimit = L->nCcalls = LUAI_MAXCSTACK + CSTACKERR;
|
g->Cstacklimit = L->nCcalls = 0;
|
||||||
incnny(L); /* main thread is always non yieldable */
|
incnny(L); /* main thread is always non yieldable */
|
||||||
g->frealloc = f;
|
g->frealloc = f;
|
||||||
g->ud = ud;
|
g->ud = ud;
|
||||||
|
|||||||
7
lstate.h
7
lstate.h
@@ -144,12 +144,6 @@
|
|||||||
/* Decrement the number of non-yieldable calls */
|
/* Decrement the number of non-yieldable calls */
|
||||||
#define decnny(L) ((L)->nCcalls -= 0x10000)
|
#define decnny(L) ((L)->nCcalls -= 0x10000)
|
||||||
|
|
||||||
/* Increment the number of non-yieldable calls and decrement nCcalls */
|
|
||||||
#define incXCcalls(L) ((L)->nCcalls += 0x10000 - CSTACKCF)
|
|
||||||
|
|
||||||
/* Decrement the number of non-yieldable calls and increment nCcalls */
|
|
||||||
#define decXCcalls(L) ((L)->nCcalls -= 0x10000 - CSTACKCF)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -389,7 +383,6 @@ LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);
|
|||||||
LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L);
|
LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L);
|
||||||
LUAI_FUNC void luaE_freeCI (lua_State *L);
|
LUAI_FUNC void luaE_freeCI (lua_State *L);
|
||||||
LUAI_FUNC void luaE_shrinkCI (lua_State *L);
|
LUAI_FUNC void luaE_shrinkCI (lua_State *L);
|
||||||
LUAI_FUNC void luaE_enterCcall (lua_State *L);
|
|
||||||
LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont);
|
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 void luaE_warnerror (lua_State *L, const char *where);
|
||||||
|
|
||||||
|
|||||||
5
ltests.h
5
ltests.h
@@ -23,11 +23,6 @@
|
|||||||
#define LUAI_ASSERT
|
#define LUAI_ASSERT
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* compiled with -O0, Lua uses a lot of C stack space... */
|
|
||||||
#undef LUAI_MAXCSTACK
|
|
||||||
#define LUAI_MAXCSTACK 400
|
|
||||||
|
|
||||||
/* to avoid warnings, and to make sure value is really unused */
|
/* to avoid warnings, and to make sure value is really unused */
|
||||||
#define UNUSED(x) (x=0, (void)(x))
|
#define UNUSED(x) (x=0, (void)(x))
|
||||||
|
|
||||||
|
|||||||
@@ -36,8 +36,8 @@
|
|||||||
** =====================================================================
|
** =====================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/* >>> move back to llimits.h
|
||||||
@@ LUAI_MAXCSTACK defines the maximum depth for nested calls and
|
@@ LUAI_MAXCCALLS defines the maximum depth for nested calls and
|
||||||
** also limits the maximum depth of other recursive algorithms in
|
** also limits the maximum depth of other recursive algorithms in
|
||||||
** the implementation, such as syntactic analysis. A value too
|
** the implementation, such as syntactic analysis. A value too
|
||||||
** large may allow the interpreter to crash (C-stack overflow).
|
** large may allow the interpreter to crash (C-stack overflow).
|
||||||
@@ -46,8 +46,8 @@
|
|||||||
** The test file 'cstack.lua' may help finding a good limit.
|
** The test file 'cstack.lua' may help finding a good limit.
|
||||||
** (It will crash with a limit too high.)
|
** (It will crash with a limit too high.)
|
||||||
*/
|
*/
|
||||||
#if !defined(LUAI_MAXCSTACK)
|
#if !defined(LUAI_MAXCCALLS)
|
||||||
#define LUAI_MAXCSTACK 2000
|
#define LUAI_MAXCCALLS 200
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
27
lvm.c
27
lvm.c
@@ -229,7 +229,7 @@ static int forprep (lua_State *L, StkId ra) {
|
|||||||
count /= l_castS2U(-(step + 1)) + 1u;
|
count /= l_castS2U(-(step + 1)) + 1u;
|
||||||
}
|
}
|
||||||
/* store the counter in place of the limit (which won't be
|
/* store the counter in place of the limit (which won't be
|
||||||
needed anymore */
|
needed anymore) */
|
||||||
setivalue(plimit, l_castU2S(count));
|
setivalue(plimit, l_castU2S(count));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1124,6 +1124,7 @@ void luaV_finishOp (lua_State *L) {
|
|||||||
|
|
||||||
|
|
||||||
void luaV_execute (lua_State *L, CallInfo *ci) {
|
void luaV_execute (lua_State *L, CallInfo *ci) {
|
||||||
|
const CallInfo *origci = ci;
|
||||||
LClosure *cl;
|
LClosure *cl;
|
||||||
TValue *k;
|
TValue *k;
|
||||||
StkId base;
|
StkId base;
|
||||||
@@ -1611,7 +1612,13 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
|||||||
if (b != 0) /* fixed number of arguments? */
|
if (b != 0) /* fixed number of arguments? */
|
||||||
L->top = ra + b; /* top signals number of arguments */
|
L->top = ra + b; /* top signals number of arguments */
|
||||||
/* else previous instruction set top */
|
/* else previous instruction set top */
|
||||||
ProtectNT(luaD_call(L, ra, nresults));
|
savepc(L); /* in case of errors */
|
||||||
|
if (luaD_precall(L, ra, nresults))
|
||||||
|
updatetrap(ci); /* C call; nothing else to be done */
|
||||||
|
else { /* Lua call: run function in this same invocation */
|
||||||
|
ci = L->ci;
|
||||||
|
goto tailcall;
|
||||||
|
}
|
||||||
vmbreak;
|
vmbreak;
|
||||||
}
|
}
|
||||||
vmcase(OP_TAILCALL) {
|
vmcase(OP_TAILCALL) {
|
||||||
@@ -1637,12 +1644,12 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
|||||||
checkstackGCp(L, 1, ra);
|
checkstackGCp(L, 1, ra);
|
||||||
}
|
}
|
||||||
if (!ttisLclosure(s2v(ra))) { /* C function? */
|
if (!ttisLclosure(s2v(ra))) { /* C function? */
|
||||||
luaD_call(L, ra, LUA_MULTRET); /* call it */
|
luaD_precall(L, ra, LUA_MULTRET); /* call it */
|
||||||
updatetrap(ci);
|
updatetrap(ci);
|
||||||
updatestack(ci); /* stack may have been relocated */
|
updatestack(ci); /* stack may have been relocated */
|
||||||
ci->func -= delta;
|
ci->func -= delta;
|
||||||
luaD_poscall(L, ci, cast_int(L->top - ra));
|
luaD_poscall(L, ci, cast_int(L->top - ra));
|
||||||
return;
|
goto ret;
|
||||||
}
|
}
|
||||||
ci->func -= delta;
|
ci->func -= delta;
|
||||||
luaD_pretailcall(L, ci, ra, b); /* prepare call frame */
|
luaD_pretailcall(L, ci, ra, b); /* prepare call frame */
|
||||||
@@ -1665,7 +1672,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
|||||||
ci->func -= ci->u.l.nextraargs + nparams1;
|
ci->func -= ci->u.l.nextraargs + nparams1;
|
||||||
L->top = ra + n; /* set call for 'luaD_poscall' */
|
L->top = ra + n; /* set call for 'luaD_poscall' */
|
||||||
luaD_poscall(L, ci, n);
|
luaD_poscall(L, ci, n);
|
||||||
return;
|
goto ret;
|
||||||
}
|
}
|
||||||
vmcase(OP_RETURN0) {
|
vmcase(OP_RETURN0) {
|
||||||
if (L->hookmask) {
|
if (L->hookmask) {
|
||||||
@@ -1679,7 +1686,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
|||||||
while (nres-- > 0)
|
while (nres-- > 0)
|
||||||
setnilvalue(s2v(L->top++)); /* all results are nil */
|
setnilvalue(s2v(L->top++)); /* all results are nil */
|
||||||
}
|
}
|
||||||
return;
|
goto ret;
|
||||||
}
|
}
|
||||||
vmcase(OP_RETURN1) {
|
vmcase(OP_RETURN1) {
|
||||||
if (L->hookmask) {
|
if (L->hookmask) {
|
||||||
@@ -1698,7 +1705,13 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
|
|||||||
setnilvalue(s2v(L->top++));
|
setnilvalue(s2v(L->top++));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
ret:
|
||||||
|
if (ci == origci)
|
||||||
|
return;
|
||||||
|
else {
|
||||||
|
ci = ci->previous;
|
||||||
|
goto tailcall;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
vmcase(OP_FORLOOP) {
|
vmcase(OP_FORLOOP) {
|
||||||
if (ttisinteger(s2v(ra + 2))) { /* integer loop? */
|
if (ttisinteger(s2v(ra + 2))) { /* integer loop? */
|
||||||
|
|||||||
@@ -127,8 +127,8 @@ else
|
|||||||
end
|
end
|
||||||
|
|
||||||
Cstacklevel = function ()
|
Cstacklevel = function ()
|
||||||
local _, _, ncalls, nci = T.stacklevel()
|
local _, _, ncalls = T.stacklevel()
|
||||||
return ncalls + nci -- number of free slots in the C stack
|
return ncalls -- number of C calls
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
-- $Id: testes/cstack.lua $
|
-- $Id: testes/cstack.lua $
|
||||||
-- See Copyright Notice in file all.lua
|
-- See Copyright Notice in file all.lua
|
||||||
|
|
||||||
|
do return end
|
||||||
|
|
||||||
local debug = require "debug"
|
local debug = require "debug"
|
||||||
|
|
||||||
print"testing C-stack overflow detection"
|
print"testing C-stack overflow detection"
|
||||||
|
|||||||
@@ -530,10 +530,9 @@ local function testrep (init, rep, close, repc, finalresult)
|
|||||||
if (finalresult) then
|
if (finalresult) then
|
||||||
assert(res() == finalresult)
|
assert(res() == finalresult)
|
||||||
end
|
end
|
||||||
s = init .. string.rep(rep, 10000)
|
s = init .. string.rep(rep, 500)
|
||||||
local res, msg = load(s) -- 10000 levels not ok
|
local res, msg = load(s) -- 500 levels not ok
|
||||||
assert(not res and (string.find(msg, "too many registers") or
|
assert(not res and string.find(msg, "too many"))
|
||||||
string.find(msg, "stack overflow")))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
testrep("local a; a", ",a", "= 1", ",1") -- multiple assignment
|
testrep("local a; a", ",a", "= 1", ",1") -- multiple assignment
|
||||||
|
|||||||
Reference in New Issue
Block a user