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 | } |