Browse Source

tail calls do not need to move whole new frame down, only its slice
up to last parameter (the rest has not been used yet)

Roberto Ierusalimschy 16 years ago
parent
commit
11d7ba79f2
1 changed files with 12 additions and 8 deletions
  1. 12 8
      lvm.c

+ 12 - 8
lvm.c

@@ -1,5 +1,5 @@
 /*
 /*
-** $Id: lvm.c,v 2.93 2009/06/17 17:50:09 roberto Exp roberto $
+** $Id: lvm.c,v 2.94 2009/07/01 20:31:25 roberto Exp roberto $
 ** Lua virtual machine
 ** Lua virtual machine
 ** See Copyright Notice in lua.h
 ** See Copyright Notice in lua.h
 */
 */
@@ -461,7 +461,7 @@ void luaV_execute (lua_State *L) {
     /* warning!! several calls may realloc the stack and invalidate `ra' */
     /* warning!! several calls may realloc the stack and invalidate `ra' */
     ra = RA(i);
     ra = RA(i);
     lua_assert(base == ci->u.l.base);
     lua_assert(base == ci->u.l.base);
-    lua_assert(base <= L->top && L->top <= L->stack + L->stacksize);
+    lua_assert(base <= L->top && L->top < L->stack + L->stacksize);
     switch (GET_OPCODE(i)) {
     switch (GET_OPCODE(i)) {
       case OP_MOVE: {
       case OP_MOVE: {
         setobjs2s(L, ra, RB(i));
         setobjs2s(L, ra, RB(i));
@@ -658,18 +658,22 @@ void luaV_execute (lua_State *L) {
           /* tail call: put called frame (n) in place of caller one (o) */
           /* tail call: put called frame (n) in place of caller one (o) */
           CallInfo *nci = L->ci;  /* called frame */
           CallInfo *nci = L->ci;  /* called frame */
           CallInfo *oci = nci->previous;  /* caller frame */
           CallInfo *oci = nci->previous;  /* caller frame */
-          StkId nfunc = nci->func;  /* called function index */
-          StkId ofunc = oci->func;
+          StkId nfunc = nci->func;  /* called function */
+          StkId ofunc = oci->func;  /* caller function */
+          /* last stack slot filled by 'precall' */
+          StkId lim = nci->u.l.base + getproto(nfunc)->numparams;
           int aux;
           int aux;
+          /* close all upvalues from previous call */
           if (cl->p->sizep > 0) luaF_close(L, oci->u.l.base);
           if (cl->p->sizep > 0) luaF_close(L, oci->u.l.base);
-          oci->u.l.base = ofunc + (nci->u.l.base - nfunc);
-          for (aux = 0; nfunc+aux < L->top; aux++)  /* move frame down */
+          /* move new frame into old one */
+          for (aux = 0; nfunc + aux < lim; aux++)
             setobjs2s(L, ofunc + aux, nfunc + aux);
             setobjs2s(L, ofunc + aux, nfunc + aux);
-          oci->top = L->top = ofunc + aux;  /* correct top */
-          lua_assert(L->top == oci->u.l.base + clvalue(ofunc)->l.p->maxstacksize);
+          oci->u.l.base = ofunc + (nci->u.l.base - nfunc);  /* correct base */
+          oci->top = L->top = ofunc + (L->top - nfunc);  /* correct top */
           oci->u.l.savedpc = nci->u.l.savedpc;
           oci->u.l.savedpc = nci->u.l.savedpc;
           oci->u.l.tailcalls++;  /* one more call lost */
           oci->u.l.tailcalls++;  /* one more call lost */
           ci = L->ci = oci;  /* remove new frame */
           ci = L->ci = oci;  /* remove new frame */
+          lua_assert(L->top == oci->u.l.base + getproto(ofunc)->maxstacksize);
           break;  /* restart luaV_execute over new Lua function */
           break;  /* restart luaV_execute over new Lua function */
         }
         }
       }
       }