diff options
| -rw-r--r-- | ldo.c | 47 | ||||
| -rw-r--r-- | ldo.h | 4 | ||||
| -rw-r--r-- | lvm.c | 42 |
3 files changed, 57 insertions, 36 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: ldo.c,v 2.171 2017/11/13 12:26:30 roberto Exp roberto $ | 2 | ** $Id: ldo.c,v 2.172 2017/11/13 15:36:52 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 | */ |
| @@ -280,14 +280,13 @@ void luaD_hook (lua_State *L, int event, int line) { | |||
| 280 | } | 280 | } |
| 281 | 281 | ||
| 282 | 282 | ||
| 283 | static void callhook (lua_State *L, CallInfo *ci) { | 283 | static void callhook (lua_State *L, CallInfo *ci, int istail) { |
| 284 | int hook; | 284 | int hook; |
| 285 | ci->u.l.trap = 1; | 285 | ci->u.l.trap = 1; |
| 286 | if (!(L->hookmask & LUA_MASKCALL)) | 286 | if (!(L->hookmask & LUA_MASKCALL)) |
| 287 | return; /* some other hook */ | 287 | return; /* some other hook */ |
| 288 | ci->u.l.savedpc++; /* hooks assume 'pc' is already incremented */ | 288 | ci->u.l.savedpc++; /* hooks assume 'pc' is already incremented */ |
| 289 | if (isLua(ci->previous) && | 289 | if (istail) { |
| 290 | GET_OPCODE(*(ci->previous->u.l.savedpc - 1)) == OP_TAILCALL) { | ||
| 291 | ci->callstatus |= CIST_TAIL; | 290 | ci->callstatus |= CIST_TAIL; |
| 292 | hook = LUA_HOOKTAILCALL; | 291 | hook = LUA_HOOKTAILCALL; |
| 293 | } | 292 | } |
| @@ -303,16 +302,18 @@ static void callhook (lua_State *L, CallInfo *ci) { | |||
| 303 | ** it in stack below original 'func' so that 'luaD_precall' can call | 302 | ** it in stack below original 'func' so that 'luaD_precall' can call |
| 304 | ** it. Raise an error if __call metafield is not a function. | 303 | ** it. Raise an error if __call metafield is not a function. |
| 305 | */ | 304 | */ |
| 306 | static void tryfuncTM (lua_State *L, StkId func) { | 305 | StkId luaD_tryfuncTM (lua_State *L, StkId func) { |
| 307 | const TValue *tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); | 306 | const TValue *tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); |
| 308 | StkId p; | 307 | StkId p; |
| 309 | if (!ttisfunction(tm)) | 308 | if (!ttisfunction(tm)) |
| 310 | luaG_typeerror(L, s2v(func), "call"); | 309 | luaG_typeerror(L, s2v(func), "call"); |
| 311 | /* Open a hole inside the stack at 'func' */ | 310 | /* Open a hole inside the stack at 'func' */ |
| 311 | checkstackp(L, 1, func); /* ensure space for metamethod */ | ||
| 312 | for (p = L->top; p > func; p--) | 312 | for (p = L->top; p > func; p--) |
| 313 | setobjs2s(L, p, p-1); | 313 | setobjs2s(L, p, p-1); |
| 314 | L->top++; /* slot ensured by caller */ | 314 | L->top++; |
| 315 | setobj2s(L, func, tm); /* tag method is the new function to be called */ | 315 | setobj2s(L, func, tm); /* metamethod is the new function to be called */ |
| 316 | return func; | ||
| 316 | } | 317 | } |
| 317 | 318 | ||
| 318 | 319 | ||
| @@ -389,6 +390,33 @@ int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres) { | |||
| 389 | 390 | ||
| 390 | 391 | ||
| 391 | /* | 392 | /* |
| 393 | ** Prepare a function for a tail call, building its call info on top | ||
| 394 | ** of the current call info. 'n' is the number of arguments plus 1 | ||
| 395 | ** (so that it includes the function itself). | ||
| 396 | */ | ||
| 397 | void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int n) { | ||
| 398 | Proto *p = clLvalue(s2v(func))->p; | ||
| 399 | int fsize = p->maxstacksize; /* frame size */ | ||
| 400 | int i; | ||
| 401 | for (i = 0; i < n; i++) /* move down function and arguments */ | ||
| 402 | setobjs2s(L, ci->func + i, func + i); | ||
| 403 | checkstackp(L, fsize, func); | ||
| 404 | for (; i < p->numparams - p->is_vararg; i++) | ||
| 405 | setnilvalue(s2v(ci->func + i)); /* complete missing parameters */ | ||
| 406 | if (p->is_vararg) { | ||
| 407 | L->top -= (func - ci->func); /* move down top */ | ||
| 408 | luaT_adjustvarargs(L, p, n - 1); | ||
| 409 | } | ||
| 410 | L->top = ci->top = ci->func + 1 + fsize; /* top for new function */ | ||
| 411 | lua_assert(ci->top <= L->stack_last); | ||
| 412 | ci->u.l.savedpc = p->code; /* starting point */ | ||
| 413 | ci->callstatus |= CIST_TAIL; | ||
| 414 | if (L->hookmask) | ||
| 415 | callhook(L, ci, 1); | ||
| 416 | } | ||
| 417 | |||
| 418 | |||
| 419 | /* | ||
| 392 | ** Prepares a function call: checks the stack, creates a new CallInfo | 420 | ** Prepares a function call: checks the stack, creates a new CallInfo |
| 393 | ** entry, fills in the relevant information, calls hook if needed. | 421 | ** entry, fills in the relevant information, calls hook if needed. |
| 394 | ** If function is a C function, does the call, too. (Otherwise, leave | 422 | ** If function is a C function, does the call, too. (Otherwise, leave |
| @@ -440,12 +468,11 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { | |||
| 440 | ci->u.l.savedpc = p->code; /* starting point */ | 468 | ci->u.l.savedpc = p->code; /* starting point */ |
| 441 | ci->callstatus = CIST_LUA; | 469 | ci->callstatus = CIST_LUA; |
| 442 | if (L->hookmask) | 470 | if (L->hookmask) |
| 443 | callhook(L, ci); | 471 | callhook(L, ci, 0); |
| 444 | return 0; | 472 | return 0; |
| 445 | } | 473 | } |
| 446 | default: { /* not a function */ | 474 | default: { /* not a function */ |
| 447 | checkstackp(L, 1, func); /* ensure space for metamethod */ | 475 | func = luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */ |
| 448 | tryfuncTM(L, func); /* try to get '__call' metamethod */ | ||
| 449 | return luaD_precall(L, func, nresults); /* now it must be a function */ | 476 | return luaD_precall(L, func, nresults); /* now it must be a function */ |
| 450 | } | 477 | } |
| 451 | } | 478 | } |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: ldo.h,v 2.31 2017/06/29 15:06:44 roberto Exp $ | 2 | ** $Id: ldo.h,v 2.33 2017/11/07 13:25:26 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 | */ |
| @@ -48,8 +48,10 @@ LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, | |||
| 48 | const char *mode); | 48 | const char *mode); |
| 49 | LUAI_FUNC void luaD_hook (lua_State *L, int event, int line); | 49 | LUAI_FUNC void luaD_hook (lua_State *L, int event, int line); |
| 50 | LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults); | 50 | LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults); |
| 51 | LUAI_FUNC void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int n); | ||
| 51 | LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); | 52 | LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); |
| 52 | LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults); | 53 | LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults); |
| 54 | LUAI_FUNC StkId luaD_tryfuncTM (lua_State *L, StkId func); | ||
| 53 | LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, | 55 | LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, |
| 54 | ptrdiff_t oldtop, ptrdiff_t ef); | 56 | ptrdiff_t oldtop, ptrdiff_t ef); |
| 55 | LUAI_FUNC int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, | 57 | LUAI_FUNC int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lvm.c,v 2.311 2017/11/16 12:59:14 roberto Exp roberto $ | 2 | ** $Id: lvm.c,v 2.312 2017/11/20 12:57:39 roberto Exp roberto $ |
| 3 | ** Lua virtual machine | 3 | ** Lua virtual machine |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -1429,31 +1429,23 @@ void luaV_execute (lua_State *L) { | |||
| 1429 | vmbreak; | 1429 | vmbreak; |
| 1430 | } | 1430 | } |
| 1431 | vmcase(OP_TAILCALL) { | 1431 | vmcase(OP_TAILCALL) { |
| 1432 | int b = GETARG_B(i); | 1432 | int b = GETARG_B(i); /* number of arguments + 1 (function) */ |
| 1433 | if (b != 0) L->top = ra+b; /* else previous instruction set top */ | 1433 | if (b != 0) |
| 1434 | L->top = ra + b; | ||
| 1435 | else /* previous instruction set top */ | ||
| 1436 | b = L->top - ra; | ||
| 1434 | lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); | 1437 | lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); |
| 1435 | savepc(L); | 1438 | if (!ttisfunction(s2v(ra))) { /* not a function? */ |
| 1436 | if (luaD_precall(L, ra, LUA_MULTRET)) /* C function? */ | 1439 | /* try to get '__call' metamethod */ |
| 1437 | updatetrap(ci); | 1440 | Protect(ra = luaD_tryfuncTM(L, ra)); |
| 1438 | else { | 1441 | b++; /* there is now one extra argument */ |
| 1439 | /* tail call: put called frame (n) in place of caller one (o) */ | 1442 | } |
| 1440 | CallInfo *nci = L->ci; /* called frame (new) */ | 1443 | if (!ttisLclosure(s2v(ra))) /* C function? */ |
| 1441 | CallInfo *oci = nci->previous; /* caller frame (old) */ | 1444 | Protect(luaD_precall(L, ra, LUA_MULTRET)); /* call it */ |
| 1442 | StkId nfunc = nci->func; /* called function */ | 1445 | else { /* tail call */ |
| 1443 | StkId ofunc = oci->func; /* caller function */ | 1446 | if (cl->p->sizep > 0) /* close upvalues from previous call */ |
| 1444 | /* last stack slot filled by 'precall' */ | 1447 | luaF_close(L, ci->func + 1); |
| 1445 | StkId lim = nfunc + 1 + getproto(s2v(nfunc))->numparams; | 1448 | luaD_pretailcall(L, ci, ra, b); /* prepare call frame */ |
| 1446 | int aux; | ||
| 1447 | /* close all upvalues from previous call */ | ||
| 1448 | if (cl->p->sizep > 0) luaF_close(L, ofunc + 1); | ||
| 1449 | /* move new frame into old one */ | ||
| 1450 | for (aux = 0; nfunc + aux < lim; aux++) | ||
| 1451 | setobjs2s(L, ofunc + aux, nfunc + aux); | ||
| 1452 | oci->top = L->top = ofunc + (L->top - nfunc); /* correct top */ | ||
| 1453 | oci->u.l.savedpc = nci->u.l.savedpc; | ||
| 1454 | oci->callstatus |= CIST_TAIL; /* function was tail called */ | ||
| 1455 | ci = L->ci = oci; /* remove new frame */ | ||
| 1456 | lua_assert(L->top == ofunc + 1 + getproto(s2v(ofunc))->maxstacksize); | ||
| 1457 | goto newframe; /* restart luaV_execute over new Lua function */ | 1449 | goto newframe; /* restart luaV_execute over new Lua function */ |
| 1458 | } | 1450 | } |
| 1459 | vmbreak; | 1451 | vmbreak; |
