diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2002-03-22 13:54:31 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2002-03-22 13:54:31 -0300 |
| commit | 00af2faae71e6388ee61ef18b2c5902a42e9bc27 (patch) | |
| tree | 9aa58a3fb85e9ba665578bbb6c669ef3149ef56e | |
| parent | e9ef7ed2d3015ff6083ae51995b153b88837b64d (diff) | |
| download | lua-00af2faae71e6388ee61ef18b2c5902a42e9bc27.tar.gz lua-00af2faae71e6388ee61ef18b2c5902a42e9bc27.tar.bz2 lua-00af2faae71e6388ee61ef18b2c5902a42e9bc27.zip | |
first implementation of proper tail call
| -rw-r--r-- | ldebug.c | 4 | ||||
| -rw-r--r-- | lvm.c | 42 |
2 files changed, 32 insertions, 14 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: ldebug.c,v 1.102 2002/03/11 12:45:00 roberto Exp roberto $ | 2 | ** $Id: ldebug.c,v 1.103 2002/03/19 12:45:25 roberto Exp roberto $ |
| 3 | ** Debug Interface | 3 | ** Debug Interface |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -296,6 +296,7 @@ static int checkopenop (const Proto *pt, int pc) { | |||
| 296 | Instruction i = pt->code[pc+1]; | 296 | Instruction i = pt->code[pc+1]; |
| 297 | switch (GET_OPCODE(i)) { | 297 | switch (GET_OPCODE(i)) { |
| 298 | case OP_CALL: | 298 | case OP_CALL: |
| 299 | case OP_TAILCALL: | ||
| 299 | case OP_RETURN: { | 300 | case OP_RETURN: { |
| 300 | check(GETARG_B(i) == 0); | 301 | check(GETARG_B(i) == 0); |
| 301 | return 1; | 302 | return 1; |
| @@ -405,6 +406,7 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) { | |||
| 405 | if (reg >= a) last = pc; /* affect all registers above base */ | 406 | if (reg >= a) last = pc; /* affect all registers above base */ |
| 406 | break; | 407 | break; |
| 407 | } | 408 | } |
| 409 | case OP_TAILCALL: | ||
| 408 | case OP_RETURN: { | 410 | case OP_RETURN: { |
| 409 | b--; /* b = num. returns */ | 411 | b--; /* b = num. returns */ |
| 410 | if (b > 0) checkreg(pt, a+b-1); | 412 | if (b > 0) checkreg(pt, a+b-1); |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lvm.c,v 1.220 2002/03/19 12:45:25 roberto Exp roberto $ | 2 | ** $Id: lvm.c,v 1.221 2002/03/20 12:52:32 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 | */ |
| @@ -314,7 +314,7 @@ static void powOp (lua_State *L, StkId ra, StkId rb, StkId rc) { | |||
| 314 | } | 314 | } |
| 315 | 315 | ||
| 316 | 316 | ||
| 317 | #define dojump(pc, i) ((pc) += GETARG_sBc(i)) | 317 | #define dojump(pc, i) ((pc) += (i)) |
| 318 | 318 | ||
| 319 | /* | 319 | /* |
| 320 | ** Executes current Lua function. Parameters are between [base,top). | 320 | ** Executes current Lua function. Parameters are between [base,top). |
| @@ -327,13 +327,13 @@ StkId luaV_execute (lua_State *L) { | |||
| 327 | const Instruction *pc; | 327 | const Instruction *pc; |
| 328 | lua_Hook linehook; | 328 | lua_Hook linehook; |
| 329 | reinit: | 329 | reinit: |
| 330 | base = L->ci->base; | ||
| 331 | cl = &clvalue(base - 1)->l; | ||
| 332 | k = cl->p->k; | ||
| 333 | linehook = L->linehook; | 330 | linehook = L->linehook; |
| 334 | L->ci->pc = &pc; | 331 | L->ci->pc = &pc; |
| 335 | L->ci->pb = &base; | ||
| 336 | pc = L->ci->savedpc; | 332 | pc = L->ci->savedpc; |
| 333 | L->ci->pb = &base; | ||
| 334 | base = L->ci->base; | ||
| 335 | cl = &clvalue(base - 1)->l; | ||
| 336 | k = cl->p->k; | ||
| 337 | /* main loop of interpreter */ | 337 | /* main loop of interpreter */ |
| 338 | for (;;) { | 338 | for (;;) { |
| 339 | const Instruction i = *pc++; | 339 | const Instruction i = *pc++; |
| @@ -343,7 +343,8 @@ StkId luaV_execute (lua_State *L) { | |||
| 343 | ra = RA(i); | 343 | ra = RA(i); |
| 344 | lua_assert(L->top <= L->stack + L->stacksize && L->top >= L->ci->base); | 344 | lua_assert(L->top <= L->stack + L->stacksize && L->top >= L->ci->base); |
| 345 | lua_assert(L->top == L->ci->top || GET_OPCODE(i) == OP_CALL || | 345 | lua_assert(L->top == L->ci->top || GET_OPCODE(i) == OP_CALL || |
| 346 | GET_OPCODE(i) == OP_RETURN || GET_OPCODE(i) == OP_SETLISTO); | 346 | GET_OPCODE(i) == OP_TAILCALL || GET_OPCODE(i) == OP_RETURN || |
| 347 | GET_OPCODE(i) == OP_SETLISTO); | ||
| 347 | switch (GET_OPCODE(i)) { | 348 | switch (GET_OPCODE(i)) { |
| 348 | case OP_MOVE: { | 349 | case OP_MOVE: { |
| 349 | setobj(ra, RB(i)); | 350 | setobj(ra, RB(i)); |
| @@ -452,7 +453,8 @@ StkId luaV_execute (lua_State *L) { | |||
| 452 | break; | 453 | break; |
| 453 | } | 454 | } |
| 454 | case OP_JMP: { | 455 | case OP_JMP: { |
| 455 | dojump(pc, i); | 456 | linehook = L->linehook; |
| 457 | dojump(pc, GETARG_sBc(i)); | ||
| 456 | break; | 458 | break; |
| 457 | } | 459 | } |
| 458 | case OP_TESTEQ: { /* skip next instruction if test fails */ | 460 | case OP_TESTEQ: { /* skip next instruction if test fails */ |
| @@ -513,14 +515,26 @@ StkId luaV_execute (lua_State *L) { | |||
| 513 | } | 515 | } |
| 514 | break; | 516 | break; |
| 515 | } | 517 | } |
| 518 | case OP_TAILCALL: { | ||
| 519 | int b = GETARG_B(i); | ||
| 520 | if (L->openupval) luaF_close(L, base); | ||
| 521 | if (b != 0) L->top = ra+b; /* else previous instruction set top */ | ||
| 522 | luaD_poscall(L, LUA_MULTRET, ra); /* move down function and args. */ | ||
| 523 | ra = luaD_precall(L, base-1); | ||
| 524 | if (ra == NULL) goto reinit; /* it is a Lua function */ | ||
| 525 | else if (ra > L->top) return NULL; /* yield??? */ | ||
| 526 | else goto ret; | ||
| 527 | } | ||
| 516 | case OP_RETURN: { | 528 | case OP_RETURN: { |
| 517 | CallInfo *ci; | ||
| 518 | int b; | 529 | int b; |
| 519 | if (L->openupval) luaF_close(L, base); | 530 | if (L->openupval) luaF_close(L, base); |
| 520 | b = GETARG_B(i); | 531 | b = GETARG_B(i); |
| 521 | if (b != 0) L->top = ra+b-1; | 532 | if (b != 0) L->top = ra+b-1; |
| 533 | lua_assert(L->ci->pc == &pc); | ||
| 534 | } | ||
| 535 | ret: { | ||
| 536 | CallInfo *ci; | ||
| 522 | ci = L->ci - 1; | 537 | ci = L->ci - 1; |
| 523 | lua_assert((ci+1)->pc == &pc); | ||
| 524 | if (ci->pc != &pc) /* previous function was running `here'? */ | 538 | if (ci->pc != &pc) /* previous function was running `here'? */ |
| 525 | return ra; /* no: return */ | 539 | return ra; /* no: return */ |
| 526 | else { /* yes: continue its execution */ | 540 | else { /* yes: continue its execution */ |
| @@ -542,7 +556,7 @@ StkId luaV_execute (lua_State *L) { | |||
| 542 | int j = GETARG_sBc(i); | 556 | int j = GETARG_sBc(i); |
| 543 | const TObject *plimit = ra+1; | 557 | const TObject *plimit = ra+1; |
| 544 | const TObject *pstep = ra+2; | 558 | const TObject *pstep = ra+2; |
| 545 | pc += j; /* jump back before tests (for error messages) */ | 559 | dojump(pc, j); /* jump back before tests (for error messages) */ |
| 546 | if (ttype(ra) != LUA_TNUMBER) | 560 | if (ttype(ra) != LUA_TNUMBER) |
| 547 | luaD_error(L, "`for' initial value must be a number"); | 561 | luaD_error(L, "`for' initial value must be a number"); |
| 548 | if (!tonumber(plimit, ra+1)) | 562 | if (!tonumber(plimit, ra+1)) |
| @@ -552,10 +566,12 @@ StkId luaV_execute (lua_State *L) { | |||
| 552 | step = nvalue(pstep); | 566 | step = nvalue(pstep); |
| 553 | index = nvalue(ra) + step; /* increment index */ | 567 | index = nvalue(ra) + step; /* increment index */ |
| 554 | limit = nvalue(plimit); | 568 | limit = nvalue(plimit); |
| 555 | if (step > 0 ? index <= limit : index >= limit) | 569 | if (step > 0 ? index <= limit : index >= limit) { |
| 556 | chgnvalue(ra, index); /* update index */ | 570 | chgnvalue(ra, index); /* update index */ |
| 571 | linehook = L->linehook; | ||
| 572 | } | ||
| 557 | else | 573 | else |
| 558 | pc -= j; /* undo jump */ | 574 | dojump(pc, -j); /* undo jump */ |
| 559 | break; | 575 | break; |
| 560 | } | 576 | } |
| 561 | case OP_TFORLOOP: { | 577 | case OP_TFORLOOP: { |
