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