diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2017-11-21 12:18:03 -0200 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2017-11-21 12:18:03 -0200 |
| commit | 14c3aa12b5a609f45b9be49e11ee862f9193a014 (patch) | |
| tree | 6ebd4e3472ee2e1b9c3f8e3c2a896f8e9d31a268 /ldo.c | |
| parent | f3ca52bfa994edacfa8fbbc6f1014724b384de9a (diff) | |
| download | lua-14c3aa12b5a609f45b9be49e11ee862f9193a014.tar.gz lua-14c3aa12b5a609f45b9be49e11ee862f9193a014.tar.bz2 lua-14c3aa12b5a609f45b9be49e11ee862f9193a014.zip | |
more direct implementation for tail calls.
Diffstat (limited to 'ldo.c')
| -rw-r--r-- | ldo.c | 47 |
1 files changed, 37 insertions, 10 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 | } |
