diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-01-28 11:39:52 -0200 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2018-01-28 11:39:52 -0200 |
commit | 89110986d7a9e81960261ae682780d5fd06dc4ac (patch) | |
tree | 5fe3d0039b2152223b58adc33a4b6c916fc853d8 | |
parent | 53979dfe0dbd7eba767ff37b1148d1e4dc9f8294 (diff) | |
download | lua-89110986d7a9e81960261ae682780d5fd06dc4ac.tar.gz lua-89110986d7a9e81960261ae682780d5fd06dc4ac.tar.bz2 lua-89110986d7a9e81960261ae682780d5fd06dc4ac.zip |
bug in tailcall of vararg functions
(when adjusting missing parameters)
-rw-r--r-- | ldo.c | 29 | ||||
-rw-r--r-- | ltm.c | 17 | ||||
-rw-r--r-- | ltm.h | 4 |
3 files changed, 26 insertions, 24 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: ldo.c,v 2.186 2018/01/10 19:19:27 roberto Exp roberto $ | 2 | ** $Id: ldo.c,v 2.187 2018/01/28 12:08:04 roberto Exp roberto $ |
3 | ** Stack and Call structure of Lua | 3 | ** Stack and Call structure of Lua |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -405,25 +405,27 @@ void luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres) { | |||
405 | 405 | ||
406 | /* | 406 | /* |
407 | ** Prepare a function for a tail call, building its call info on top | 407 | ** Prepare a function for a tail call, building its call info on top |
408 | ** of the current call info. 'n' is the number of arguments plus 1 | 408 | ** of the current call info. 'narg1' is the number of arguments plus 1 |
409 | ** (so that it includes the function itself). | 409 | ** (so that it includes the function itself). |
410 | */ | 410 | */ |
411 | void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int n) { | 411 | void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1) { |
412 | Proto *p = clLvalue(s2v(func))->p; | 412 | Proto *p = clLvalue(s2v(func))->p; |
413 | int fsize = p->maxstacksize; /* frame size */ | 413 | int fsize = p->maxstacksize; /* frame size */ |
414 | int nfixparams = p->numparams; | ||
414 | int i; | 415 | int i; |
415 | for (i = 0; i < n; i++) /* move down function and arguments */ | 416 | for (i = 0; i < narg1; i++) /* move down function and arguments */ |
416 | setobjs2s(L, ci->func + i, func + i); | 417 | setobjs2s(L, ci->func + i, func + i); |
417 | checkstackp(L, fsize, func); | 418 | checkstackp(L, fsize, func); |
418 | for (; i <= p->numparams; i++) | 419 | func = ci->func; /* moved-down function */ |
419 | setnilvalue(s2v(ci->func + i)); /* complete missing arguments */ | 420 | for (; narg1 <= nfixparams; narg1++) |
420 | ci->top = ci->func + 1 + fsize; /* top for new function */ | 421 | setnilvalue(s2v(func + narg1)); /* complete missing arguments */ |
422 | ci->top = func + 1 + fsize; /* top for new function */ | ||
421 | lua_assert(ci->top <= L->stack_last); | 423 | lua_assert(ci->top <= L->stack_last); |
422 | ci->u.l.savedpc = p->code; /* starting point */ | 424 | ci->u.l.savedpc = p->code; /* starting point */ |
423 | ci->callstatus |= CIST_TAIL; | 425 | ci->callstatus |= CIST_TAIL; |
424 | if (p->is_vararg) { | 426 | if (p->is_vararg) { |
425 | L->top -= (func - ci->func); /* move down top */ | 427 | L->top = func + narg1; /* set top */ |
426 | luaT_adjustvarargs(L, p, n - 1); | 428 | luaT_adjustvarargs(L, nfixparams, narg1 - 1); |
427 | } | 429 | } |
428 | if (L->hookmask) | 430 | if (L->hookmask) |
429 | hookcall(L, ci, 1); | 431 | hookcall(L, ci, 1); |
@@ -464,12 +466,13 @@ void luaD_call (lua_State *L, StkId func, int nresults) { | |||
464 | luaD_poscall(L, ci, L->top - n, n); | 466 | luaD_poscall(L, ci, L->top - n, n); |
465 | break; | 467 | break; |
466 | } | 468 | } |
467 | case LUA_TLCL: { /* Lua function: prepare its call */ | 469 | case LUA_TLCL: { /* Lua function */ |
468 | Proto *p = clLvalue(funcv)->p; | 470 | Proto *p = clLvalue(funcv)->p; |
469 | int n = cast_int(L->top - func) - 1; /* number of real arguments */ | 471 | int narg = cast_int(L->top - func) - 1; /* number of real arguments */ |
472 | int nfixparams = p->numparams; | ||
470 | int fsize = p->maxstacksize; /* frame size */ | 473 | int fsize = p->maxstacksize; /* frame size */ |
471 | checkstackp(L, fsize, func); | 474 | checkstackp(L, fsize, func); |
472 | for (; n < p->numparams; n++) | 475 | for (; narg < nfixparams; narg++) |
473 | setnilvalue(s2v(L->top++)); /* complete missing arguments */ | 476 | setnilvalue(s2v(L->top++)); /* complete missing arguments */ |
474 | ci = next_ci(L); /* now 'enter' new function */ | 477 | ci = next_ci(L); /* now 'enter' new function */ |
475 | ci->nresults = nresults; | 478 | ci->nresults = nresults; |
@@ -479,7 +482,7 @@ void luaD_call (lua_State *L, StkId func, int nresults) { | |||
479 | ci->u.l.savedpc = p->code; /* starting point */ | 482 | ci->u.l.savedpc = p->code; /* starting point */ |
480 | ci->callstatus = 0; | 483 | ci->callstatus = 0; |
481 | if (p->is_vararg) | 484 | if (p->is_vararg) |
482 | luaT_adjustvarargs(L, p, n); /* may invoke GC */ | 485 | luaT_adjustvarargs(L, nfixparams, narg); /* may invoke GC */ |
483 | if (L->hookmask) | 486 | if (L->hookmask) |
484 | hookcall(L, ci, 0); | 487 | hookcall(L, ci, 0); |
485 | luaV_execute(L, ci); /* run the function */ | 488 | luaV_execute(L, ci); /* run the function */ |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: ltm.c,v 2.56 2017/12/28 15:42:57 roberto Exp roberto $ | 2 | ** $Id: ltm.c,v 2.57 2018/01/28 12:08:04 roberto Exp roberto $ |
3 | ** Tag methods | 3 | ** Tag methods |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -216,21 +216,20 @@ int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2, | |||
216 | } | 216 | } |
217 | 217 | ||
218 | 218 | ||
219 | void luaT_adjustvarargs (lua_State *L, Proto *p, int actual) { | 219 | void luaT_adjustvarargs (lua_State *L, int nfixparams, int actual) { |
220 | int i; | 220 | int i; |
221 | Table *vtab; | 221 | Table *vtab; |
222 | TValue nname; | 222 | TValue nname; |
223 | int nfixparams = p->numparams; /* number of fixed parameters */ | 223 | int nextra = actual - nfixparams; /* number of extra arguments */ |
224 | actual -= nfixparams; /* number of extra arguments */ | ||
225 | vtab = luaH_new(L); /* create vararg table */ | 224 | vtab = luaH_new(L); /* create vararg table */ |
226 | sethvalue2s(L, L->top, vtab); /* anchor it for resizing */ | 225 | sethvalue2s(L, L->top, vtab); /* anchor it for resizing */ |
227 | L->top++; /* space ensured by caller */ | 226 | L->top++; /* space ensured by caller */ |
228 | luaH_resize(L, vtab, actual, 1); | 227 | luaH_resize(L, vtab, nextra, 1); |
229 | for (i = 0; i < actual; i++) /* put extra arguments into vararg table */ | 228 | for (i = 0; i < nextra; i++) /* put extra arguments into vararg table */ |
230 | setobj2n(L, &vtab->array[i], s2v(L->top - actual + i - 1)); | 229 | setobj2n(L, &vtab->array[i], s2v(L->top - nextra + i - 1)); |
231 | setsvalue(L, &nname, G(L)->nfield); /* get field 'n' */ | 230 | setsvalue(L, &nname, G(L)->nfield); /* get field 'n' */ |
232 | setivalue(luaH_set(L, vtab, &nname), actual); /* store counter there */ | 231 | setivalue(luaH_set(L, vtab, &nname), nextra); /* store counter there */ |
233 | L->top -= actual; /* remove extra elements from the stack */ | 232 | L->top -= nextra; /* remove extra elements from the stack */ |
234 | sethvalue2s(L, L->top - 1, vtab); /* move table to new top */ | 233 | sethvalue2s(L, L->top - 1, vtab); /* move table to new top */ |
235 | luaC_checkGC(L); | 234 | luaC_checkGC(L); |
236 | } | 235 | } |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: ltm.h,v 2.27 2017/11/27 17:44:31 roberto Exp roberto $ | 2 | ** $Id: ltm.h,v 2.28 2017/12/13 18:32:09 roberto Exp roberto $ |
3 | ** Tag methods | 3 | ** Tag methods |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -77,7 +77,7 @@ LUAI_FUNC int luaT_callorderTM (lua_State *L, const TValue *p1, | |||
77 | LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2, | 77 | LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2, |
78 | int inv, TMS event); | 78 | int inv, TMS event); |
79 | 79 | ||
80 | LUAI_FUNC void luaT_adjustvarargs (lua_State *L, Proto *p, int actual); | 80 | LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams, int actual); |
81 | LUAI_FUNC void luaT_getvarargs (lua_State *L, TValue *t, StkId where, | 81 | LUAI_FUNC void luaT_getvarargs (lua_State *L, TValue *t, StkId where, |
82 | int wanted); | 82 | int wanted); |
83 | 83 | ||