Преглед на файлове

back to 'CallInfo' (no gains with its removal)

Roberto Ierusalimschy преди 7 години
родител
ревизия
ad0704e40c
променени са 13 файла, в които са добавени 394 реда и са изтрити 370 реда
  1. 39 42
      lapi.c
  2. 4 5
      lapi.h
  3. 71 90
      ldebug.c
  4. 95 95
      ldo.c
  5. 3 2
      ldo.h
  6. 3 3
      lgc.c
  7. 1 31
      lobject.h
  8. 55 8
      lstate.c
  9. 40 10
      lstate.h
  10. 12 11
      ltests.c
  11. 3 3
      ltm.c
  12. 2 3
      lua.h
  13. 66 67
      lvm.c

+ 39 - 42
lapi.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lapi.c,v 2.274 2017/11/03 12:12:30 roberto Exp roberto $
+** $Id: lapi.c,v 2.273 2017/11/02 11:28:56 roberto Exp $
 ** Lua API
 ** See Copyright Notice in lua.h
 */
@@ -10,7 +10,6 @@
 #include "lprefix.h"
 
 
-#include <limits.h>
 #include <stdarg.h>
 #include <string.h>
 
@@ -59,14 +58,15 @@ const char lua_ident[] =
 
 
 static TValue *index2value (lua_State *L, int idx) {
+  CallInfo *ci = L->ci;
   if (idx > 0) {
-    StkId o = L->func + idx;
-    api_check(L, idx < L->func->stkci.framesize, "unacceptable index");
+    StkId o = ci->func + idx;
+    api_check(L, idx <= L->ci->top - (ci->func + 1), "unacceptable index");
     if (o >= L->top) return NONVALIDVALUE;
     else return s2v(o);
   }
   else if (!ispseudo(idx)) {  /* negative index */
-    api_check(L, idx != 0 && -idx < L->func->stkci.framesize, "invalid index");
+    api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index");
     return s2v(L->top + idx);
   }
   else if (idx == LUA_REGISTRYINDEX)
@@ -74,10 +74,10 @@ static TValue *index2value (lua_State *L, int idx) {
   else {  /* upvalues */
     idx = LUA_REGISTRYINDEX - idx;
     api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large");
-    if (ttislcf(s2v(L->func)))  /* light C function? */
+    if (ttislcf(s2v(ci->func)))  /* light C function? */
       return NONVALIDVALUE;  /* it has no upvalues */
     else {
-      CClosure *func = clCvalue(s2v(L->func));
+      CClosure *func = clCvalue(s2v(ci->func));
       return (idx <= func->nupvalues) ? &func->upvalue[idx-1] : NONVALIDVALUE;
     }
   }
@@ -85,13 +85,14 @@ static TValue *index2value (lua_State *L, int idx) {
 
 
 static StkId index2stack (lua_State *L, int idx) {
+  CallInfo *ci = L->ci;
   if (idx > 0) {
-    StkId o = L->func + idx;
+    StkId o = ci->func + idx;
     api_check(L, o < L->top, "unacceptable index");
     return o;
   }
   else {    /* non-positive index */
-    api_check(L, idx != 0 && -idx <= L->top - (L->func + 1), "invalid index");
+    api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index");
     api_check(L, !ispseudo(idx), "invalid index");
     return L->top + idx;
   }
@@ -110,12 +111,10 @@ static void growstack (lua_State *L, void *ud) {
 
 LUA_API int lua_checkstack (lua_State *L, int n) {
   int res;
-  int frameuse = L->top - L->func;
+  CallInfo *ci = L->ci;
   lua_lock(L);
   api_check(L, n >= 0, "negative 'n'");
-  if (n >= USHRT_MAX - frameuse)
-    res = 0;  /* frame size overflow */
-  else if (L->stack_last - L->top > n)  /* stack large enough? */
+  if (L->stack_last - L->top > n)  /* stack large enough? */
     res = 1;  /* yes; check is OK */
   else {  /* no; need to grow stack */
     int inuse = cast_int(L->top - L->stack) + EXTRA_STACK;
@@ -124,8 +123,8 @@ LUA_API int lua_checkstack (lua_State *L, int n) {
     else  /* try to grow stack */
       res = (luaD_rawrunprotected(L, &growstack, &n) == LUA_OK);
   }
-  if (res && L->func->stkci.framesize < frameuse + n)
-    L->func->stkci.framesize = frameuse + n;  /* adjust frame size */
+  if (res && ci->top < L->top + n)
+    ci->top = L->top + n;  /* adjust frame top */
   lua_unlock(L);
   return res;
 }
@@ -137,7 +136,7 @@ LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) {
   lua_lock(to);
   api_checknelems(from, n);
   api_check(from, G(from) == G(to), "moving among independent states");
-  api_check(from, functop(to->func) - to->top >= n, "stack overflow");
+  api_check(from, to->ci->top - to->top >= n, "stack overflow");
   from->top -= n;
   for (i = 0; i < n; i++) {
     setobjs2s(to, to->top, from->top + i);
@@ -176,17 +175,17 @@ LUA_API const lua_Number *lua_version (lua_State *L) {
 LUA_API int lua_absindex (lua_State *L, int idx) {
   return (idx > 0 || ispseudo(idx))
          ? idx
-         : cast_int(L->top - L->func) + idx;
+         : cast_int(L->top - L->ci->func) + idx;
 }
 
 
 LUA_API int lua_gettop (lua_State *L) {
-  return cast_int(L->top - (L->func + 1));
+  return cast_int(L->top - (L->ci->func + 1));
 }
 
 
 LUA_API void lua_settop (lua_State *L, int idx) {
-  StkId func = L->func;
+  StkId func = L->ci->func;
   lua_lock(L);
   if (idx >= 0) {
     api_check(L, idx <= L->stack_last - (func + 1), "new top too large");
@@ -244,7 +243,7 @@ LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) {
   api_checkvalidindex(L, to);
   setobj(L, to, fr);
   if (isupvalue(toidx))  /* function upvalue? */
-    luaC_barrier(L, clCvalue(s2v(L->func)), fr);
+    luaC_barrier(L, clCvalue(s2v(L->ci->func)), fr);
   /* LUA_REGISTRYINDEX does not need gc barrier
      (collector revisits it before finishing collection) */
   lua_unlock(L);
@@ -932,24 +931,23 @@ LUA_API void lua_setuservalue (lua_State *L, int idx) {
 
 
 #define checkresults(L,na,nr) \
-     api_check(L, (nr) == LUA_MULTRET || \
-                  (functop(L->func) - L->top >= (nr) - (na)), \
-	"results from function overflow current frame size")
+     api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)), \
+	"results from function overflow current stack size")
 
 
 LUA_API void lua_callk (lua_State *L, int nargs, int nresults,
                         lua_KContext ctx, lua_KFunction k) {
   StkId func;
   lua_lock(L);
-  api_check(L, k == NULL || !isLua(L->func),
+  api_check(L, k == NULL || !isLua(L->ci),
     "cannot use continuations inside hooks");
   api_checknelems(L, nargs+1);
   api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread");
   checkresults(L, nargs, nresults);
   func = L->top - (nargs+1);
   if (k != NULL && L->nny == 0) {  /* need to prepare continuation? */
-    L->func->stkci.u.c.k = k;  /* save continuation */
-    L->func->stkci.u.c.ctx = ctx;  /* save context */
+    L->ci->u.c.k = k;  /* save continuation */
+    L->ci->u.c.ctx = ctx;  /* save context */
     luaD_call(L, func, nresults);  /* do the call */
   }
   else  /* no continuation or no yieldable */
@@ -980,38 +978,37 @@ LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc,
                         lua_KContext ctx, lua_KFunction k) {
   struct CallS c;
   int status;
-  ptrdiff_t efunc;
+  ptrdiff_t func;
   lua_lock(L);
-  api_check(L, k == NULL || !isLua(L->func),
+  api_check(L, k == NULL || !isLua(L->ci),
     "cannot use continuations inside hooks");
   api_checknelems(L, nargs+1);
   api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread");
   checkresults(L, nargs, nresults);
   if (errfunc == 0)
-    efunc = 0;
+    func = 0;
   else {
     StkId o = index2stack(L, errfunc);
-    efunc = savestack(L, o);
+    func = savestack(L, o);
   }
   c.func = L->top - (nargs+1);  /* function to be called */
   if (k == NULL || L->nny > 0) {  /* no continuation or no yieldable? */
     c.nresults = nresults;  /* do a 'conventional' protected call */
-    status = luaD_pcall(L, f_call, &c, savestack(L, c.func), efunc);
+    status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func);
   }
   else {  /* prepare continuation (call is already protected by 'resume') */
-    StkId func = L->func;
-    func->stkci.u.c.k = k;  /* save continuation */
-    func->stkci.u.c.ctx = ctx;  /* save context */
+    CallInfo *ci = L->ci;
+    ci->u.c.k = k;  /* save continuation */
+    ci->u.c.ctx = ctx;  /* save context */
     /* save information for error recovery */
-    func->stkci.u2.funcidx = c.func - func;
-    func->stkci.u.c.old_errfunc = L->errfunc;
-    L->errfunc = efunc;
-    setoah(callstatus(func), L->allowhook);  /* save value of 'allowhook' */
-    callstatus(func) |= CIST_YPCALL;  /* function can do error recovery */
+    ci->u2.funcidx = savestack(L, c.func);
+    ci->u.c.old_errfunc = L->errfunc;
+    L->errfunc = func;
+    setoah(ci->callstatus, L->allowhook);  /* save value of 'allowhook' */
+    ci->callstatus |= CIST_YPCALL;  /* function can do error recovery */
     luaD_call(L, c.func, nresults);  /* do the call */
-    func = L->func;  /* previous call can reallocate stack */
-    callstatus(func) &= ~CIST_YPCALL;
-    L->errfunc = func->stkci.u.c.old_errfunc;
+    ci->callstatus &= ~CIST_YPCALL;
+    L->errfunc = ci->u.c.old_errfunc;
     status = LUA_OK;  /* if it is here, there were no errors */
   }
   adjustresults(L, nresults);

+ 4 - 5
lapi.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lapi.h,v 2.10 2017/11/01 18:20:48 roberto Exp roberto $
+** $Id: lapi.h,v 2.10 2017/11/01 18:20:48 roberto Exp $
 ** Auxiliary functions from Lua API
 ** See Copyright Notice in lua.h
 */
@@ -11,14 +11,13 @@
 #include "llimits.h"
 #include "lstate.h"
 
-#define api_incr_top(L)   {L->top++; api_check(L, L->top <= functop(L->func), \
+#define api_incr_top(L)   {L->top++; api_check(L, L->top <= L->ci->top, \
 				"stack overflow");}
 
 #define adjustresults(L,nres) \
-    { if ((nres) == LUA_MULTRET && functop(L->func) < L->top) \
-      setfunctop(L->func, L->top); }
+    { if ((nres) == LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; }
 
-#define api_checknelems(L,n)	api_check(L, (n) < (L->top - L->func), \
+#define api_checknelems(L,n)	api_check(L, (n) < (L->top - L->ci->func), \
 				  "not enough elements in the stack")
 
 

+ 71 - 90
ldebug.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ldebug.c,v 2.138 2017/11/03 19:33:22 roberto Exp roberto $
+** $Id: ldebug.c,v 2.135 2017/11/02 11:28:56 roberto Exp $
 ** Debug Interface
 ** See Copyright Notice in lua.h
 */
@@ -34,17 +34,17 @@
 #define noLuaClosure(f)		((f) == NULL || (f)->c.tt == LUA_TCCL)
 
 
-/* Active Lua function (given stack function) */
-#define ci_func(func)		(clLvalue(s2v(func)))
+/* Active Lua function (given call info) */
+#define ci_func(ci)		(clLvalue(s2v((ci)->func)))
 
 
-static const char *funcnamefromcode (lua_State *L, StkId stkf,
+static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
                                     const char **name);
 
 
-static int currentpc (StkId func) {
-  lua_assert(isLua(func));
-  return pcRel(func->stkci.u.l.savedpc, ci_func(func)->p);
+static int currentpc (CallInfo *ci) {
+  lua_assert(isLua(ci));
+  return pcRel(ci->u.l.savedpc, ci_func(ci)->p);
 }
 
 
@@ -101,8 +101,8 @@ int luaG_getfuncline (Proto *f, int pc) {
 }
 
 
-static int currentline (StkId func) {
-  return luaG_getfuncline(ci_func(func)->p, currentpc(func));
+static int currentline (CallInfo *ci) {
+  return luaG_getfuncline(ci_func(ci)->p, currentpc(ci));
 }
 
 
@@ -120,8 +120,8 @@ LUA_API void lua_sethook (lua_State *L, lua_Hook func, int mask, int count) {
     mask = 0;
     func = NULL;
   }
-  if (isLua(L->func))
-    L->oldpc = L->func->stkci.u.l.savedpc;
+  if (isLua(L->ci))
+    L->oldpc = L->ci->u.l.savedpc;
   L->hook = func;
   L->basehookcount = count;
   resethookcount(L);
@@ -146,17 +146,14 @@ LUA_API int lua_gethookcount (lua_State *L) {
 
 LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) {
   int status;
-  StkId func;
+  CallInfo *ci;
   if (level < 0) return 0;  /* invalid (negative) level */
   lua_lock(L);
-  for (func = L->func;
-       level > 0 && func->stkci.previous != 0;
-       func -= func->stkci.previous)
+  for (ci = L->ci; level > 0 && ci != &L->base_ci; ci = ci->previous)
     level--;
-  if (level == 0 && func->stkci.previous != 0) {  /* level found? */
+  if (level == 0 && ci != &L->base_ci) {  /* level found? */
     status = 1;
-    ar->i_actf = func - L->stack;
-    ar->i_actL = L;
+    ar->i_ci = ci;
   }
   else status = 0;  /* no such level */
   lua_unlock(L);
@@ -171,34 +168,24 @@ static const char *upvalname (Proto *p, int uv) {
 }
 
 
-static StkId findcalled (lua_State *L, StkId caller) {
-  StkId func = L->func;
-  for (;;) {
-    StkId previous = func - func->stkci.previous;
-    lua_assert(previous < func);
-    if (previous == caller)
-      return func;
-    else
-      func = previous;
-  }
-}
-
-
-static const char *findlocal (lua_State *L, const lua_Debug *ar,
-                                            int n, StkId *pos) {
+static const char *findlocal (lua_State *L, CallInfo *ci, int n,
+                              StkId *pos) {
   const char *name = NULL;
-  StkId stkf = ar->i_actL->stack + ar->i_actf;
-  if (isLua(stkf)) {
-    name = luaF_getlocalname(ci_func(stkf)->p, n, currentpc(stkf));
+  StkId base;
+  if (isLua(ci)) {
+    base = ci->func + 1;
+    name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci));
   }
+  else
+    base = ci->func + 1;
   if (name == NULL) {  /* no 'standard' name? */
-    StkId limit = (stkf == L->func) ? L->top : findcalled(L, stkf);
-    if (limit - stkf > n && n > 0)  /* is 'n' inside 'ci' stack? */
+    StkId limit = (ci == L->ci) ? L->top : ci->next->func;
+    if (limit - base >= n && n > 0)  /* is 'n' inside 'ci' stack? */
       name = "(*temporary)";  /* generic name for any valid slot */
     else
       return NULL;  /* no name */
   }
-  *pos = stkf + n;
+  *pos = base + (n - 1);
   return name;
 }
 
@@ -214,7 +201,7 @@ LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
   }
   else {  /* active function; get information through 'ar' */
     StkId pos = NULL;  /* to avoid warnings */
-    name = findlocal(L, ar, n, &pos);
+    name = findlocal(L, ar->i_ci, n, &pos);
     if (name) {
       setobjs2s(L, L->top, pos);
       api_incr_top(L);
@@ -229,7 +216,7 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
   StkId pos = NULL;  /* to avoid warnings */
   const char *name;
   lua_lock(L);
-  name = findlocal(L, ar, n, &pos);
+  name = findlocal(L, ar->i_ci, n, &pos);
   if (name) {
     setobjs2s(L, pos, L->top - 1);
     L->top--;  /* pop value */
@@ -287,25 +274,22 @@ static void collectvalidlines (lua_State *L, Closure *f) {
 }
 
 
-static const char *getfuncname (lua_State *L, StkId stkf, const char **name) {
-  if (stkf == NULL)  /* no function? */
+static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
+  if (ci == NULL)  /* no 'ci'? */
     return NULL;  /* no info */
-  else if (callstatus(stkf) & CIST_FIN) {  /* is this a finalizer? */
+  else if (ci->callstatus & CIST_FIN) {  /* is this a finalizer? */
     *name = "__gc";
     return "metamethod";  /* report it as such */
   }
   /* calling function is a known Lua function? */
-  else {
-    StkId previous = stkf - stkf->stkci.previous;
-    if (!(callstatus(stkf) & CIST_TAIL) && isLua(previous))
-      return funcnamefromcode(L, previous, name);
-    else return NULL;  /* no way to find a name */
-  }
+  else if (!(ci->callstatus & CIST_TAIL) && isLua(ci->previous))
+    return funcnamefromcode(L, ci->previous, name);
+  else return NULL;  /* no way to find a name */
 }
 
 
 static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
-                       Closure *f, StkId stkf) {
+                       Closure *f, CallInfo *ci) {
   int status = 1;
   for (; *what; what++) {
     switch (*what) {
@@ -314,7 +298,7 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
         break;
       }
       case 'l': {
-        ar->currentline = (stkf && isLua(stkf)) ? currentline(stkf) : -1;
+        ar->currentline = (ci && isLua(ci)) ? currentline(ci) : -1;
         break;
       }
       case 'u': {
@@ -330,11 +314,11 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
         break;
       }
       case 't': {
-        ar->istailcall = (stkf) ? callstatus(stkf) & CIST_TAIL : 0;
+        ar->istailcall = (ci) ? ci->callstatus & CIST_TAIL : 0;
         break;
       }
       case 'n': {
-        ar->namewhat = getfuncname(L, stkf, &ar->name);
+        ar->namewhat = getfuncname(L, ci, &ar->name);
         if (ar->namewhat == NULL) {
           ar->namewhat = "";  /* not found */
           ar->name = NULL;
@@ -354,23 +338,23 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
 LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
   int status;
   Closure *cl;
-  StkId stkf;
+  CallInfo *ci;
   TValue *func;
   lua_lock(L);
   if (*what == '>') {
-    stkf = NULL;
+    ci = NULL;
     func = s2v(L->top - 1);
     api_check(L, ttisfunction(func), "function expected");
     what++;  /* skip the '>' */
     L->top--;  /* pop function */
   }
   else {
-    stkf = ar->i_actL->stack + ar->i_actf;
-    func = s2v(stkf);
+    ci = ar->i_ci;
+    func = s2v(ci->func);
     lua_assert(ttisfunction(func));
   }
   cl = ttisclosure(func) ? clvalue(func) : NULL;
-  status = auxgetinfo(L, what, ar, cl, stkf);
+  status = auxgetinfo(L, what, ar, cl, ci);
   if (strchr(what, 'f')) {
     setobj2s(L, L->top, func);
     api_incr_top(L);
@@ -559,13 +543,13 @@ static const char *gxf (Proto *p, int pc, Instruction i, int isup) {
 ** Returns what the name is (e.g., "for iterator", "method",
 ** "metamethod") and sets '*name' to point to the name.
 */
-static const char *funcnamefromcode (lua_State *L, StkId stkf,
+static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
                                      const char **name) {
   TMS tm = (TMS)0;  /* (initial value avoids warnings) */
-  Proto *p = ci_func(stkf)->p;  /* calling function */
-  int pc = currentpc(stkf);  /* calling instruction index */
+  Proto *p = ci_func(ci)->p;  /* calling function */
+  int pc = currentpc(ci);  /* calling instruction index */
   Instruction i = p->code[pc];  /* calling instruction */
-  if (callstatus(stkf) & CIST_HOOKED) {  /* was it called inside a hook? */
+  if (ci->callstatus & CIST_HOOKED) {  /* was it called inside a hook? */
     *name = "?";
     return "hook";
   }
@@ -621,10 +605,10 @@ static const char *funcnamefromcode (lua_State *L, StkId stkf,
 ** not ISO C, but it should not crash a program; the subsequent
 ** checks are ISO C and ensure a correct result.
 */
-static int isinstack (lua_State *L, const TValue *o) {
-  StkId base = L->stack;
+static int isinstack (CallInfo *ci, const TValue *o) {
+  StkId base = ci->func + 1;
   ptrdiff_t i = cast(StkId, o) - base;
-  return (0 <= i && i < (L->top - base) && s2v(base + i) == o);
+  return (0 <= i && i < (ci->top - base) && s2v(base + i) == o);
 }
 
 
@@ -633,9 +617,9 @@ static int isinstack (lua_State *L, const TValue *o) {
 ** with instructions OP_GETTABUP/OP_SETTABUP, which operate directly on
 ** upvalues.)
 */
-static const char *getupvalname (StkId stkf, const TValue *o,
+static const char *getupvalname (CallInfo *ci, const TValue *o,
                                  const char **name) {
-  LClosure *c = ci_func(stkf);
+  LClosure *c = ci_func(ci);
   int i;
   for (i = 0; i < c->nupvalues; i++) {
     if (c->upvals[i]->v == o) {
@@ -649,13 +633,13 @@ static const char *getupvalname (StkId stkf, const TValue *o,
 
 static const char *varinfo (lua_State *L, const TValue *o) {
   const char *name = NULL;  /* to avoid warnings */
-  StkId stkf = L->func;
+  CallInfo *ci = L->ci;
   const char *kind = NULL;
-  if (isLua(stkf)) {
-    kind = getupvalname(stkf, o, &name);  /* check whether 'o' is an upvalue */
-    if (!kind && isinstack(L, o))  /* no? try a register */
-      kind = getobjname(ci_func(stkf)->p, currentpc(stkf),
-                        cast_int(cast(StkId, o) - (stkf + 1)), &name);
+  if (isLua(ci)) {
+    kind = getupvalname(ci, o, &name);  /* check whether 'o' is an upvalue */
+    if (!kind && isinstack(ci, o))  /* no? try a register */
+      kind = getobjname(ci_func(ci)->p, currentpc(ci),
+                        cast_int(cast(StkId, o) - (ci->func + 1)), &name);
   }
   return (kind) ? luaO_pushfstring(L, " (%s '%s')", kind, name) : "";
 }
@@ -728,16 +712,15 @@ l_noret luaG_errormsg (lua_State *L) {
 
 
 l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
-  StkId func;
+  CallInfo *ci = L->ci;
   const char *msg;
   va_list argp;
   luaC_checkGC(L);  /* error message uses memory */
   va_start(argp, fmt);
   msg = luaO_pushvfstring(L, fmt, argp);  /* format message */
   va_end(argp);
-  func = L->func;  /* previous calls can change the stack */
-  if (isLua(func))  /* if Lua function, add source:line information */
-    luaG_addinfo(L, msg, ci_func(func)->p->source, currentline(func));
+  if (isLua(ci))  /* if Lua function, add source:line information */
+    luaG_addinfo(L, msg, ci_func(ci)->p->source, currentline(ci));
   luaG_errormsg(L);
 }
 
@@ -756,37 +739,35 @@ static int changedline (Proto *p, int oldpc, int newpc) {
 
 
 void luaG_traceexec (lua_State *L) {
-  StkId func = L->func;
+  CallInfo *ci = L->ci;
   lu_byte mask = L->hookmask;
   int counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT));
   if (counthook)
     resethookcount(L);  /* reset count */
   else if (!(mask & LUA_MASKLINE))
     return;  /* no line hook and count != 0; nothing to be done */
-  if (callstatus(func) & CIST_HOOKYIELD) {  /* called hook last time? */
-    callstatus(func) &= ~CIST_HOOKYIELD;  /* erase mark */
+  if (ci->callstatus & CIST_HOOKYIELD) {  /* called hook last time? */
+    ci->callstatus &= ~CIST_HOOKYIELD;  /* erase mark */
     return;  /* do not call hook again (VM yielded, so it did not move) */
   }
   if (counthook)
     luaD_hook(L, LUA_HOOKCOUNT, -1);  /* call count hook */
   if (mask & LUA_MASKLINE) {
-    Proto *p = ci_func(func)->p;
-    int npc = pcRel(func->stkci.u.l.savedpc, p);
+    Proto *p = ci_func(ci)->p;
+    int npc = pcRel(ci->u.l.savedpc, p);
     if (npc == 0 ||  /* call linehook when enter a new function, */
-        func->stkci.u.l.savedpc <= L->oldpc ||  /* when jump back (loop), */
-        changedline(p, pcRel(L->oldpc, p), npc)) {  /* when enter new line */
+        ci->u.l.savedpc <= L->oldpc ||  /* when jump back (loop), or when */
+        changedline(p, pcRel(L->oldpc, p), npc)) {  /* enter new line */
       int newline = luaG_getfuncline(p, npc);  /* new line */
       luaD_hook(L, LUA_HOOKLINE, newline);  /* call line hook */
     }
   }
-  func = L->func;  /* previous calls can reallocate stack */
-  L->oldpc = func->stkci.u.l.savedpc;
+  L->oldpc = ci->u.l.savedpc;
   if (L->status == LUA_YIELD) {  /* did hook yield? */
     if (counthook)
       L->hookcount = 1;  /* undo decrement to zero */
-    /* undo increment (resume will increment it again) */
-    func->stkci.u.l.savedpc--;
-    callstatus(func) |= CIST_HOOKYIELD;  /* mark that it yielded */
+    ci->u.l.savedpc--;  /* undo increment (resume will increment it again) */
+    ci->callstatus |= CIST_HOOKYIELD;  /* mark that it yielded */
     luaD_throw(L, LUA_YIELD);
   }
 }

+ 95 - 95
ldo.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ldo.c,v 2.168 2017/11/03 20:41:05 roberto Exp roberto $
+** $Id: ldo.c,v 2.165 2017/11/02 11:28:56 roberto Exp $
 ** Stack and Call structure of Lua
 ** See Copyright Notice in lua.h
 */
@@ -123,8 +123,8 @@ l_noret luaD_throw (lua_State *L, int errcode) {
     else {  /* no handler at all; abort */
       if (g->panic) {  /* panic function? */
         seterrorobj(L, errcode, L->top);  /* assume EXTRA_STACK */
-        if (functop(L->func) < L->top)  /* check invariant */
-          setfunctop(L->func, L->top);
+        if (L->ci->top < L->top)
+          L->ci->top = L->top;  /* pushing msg. can break this invariant */
         lua_unlock(L);
         g->panic(L);  /* call panic function (last chance to jump out) */
       }
@@ -157,11 +157,15 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
 ** ===================================================================
 */
 static void correctstack (lua_State *L, StkId oldstack) {
+  CallInfo *ci;
   UpVal *up;
   L->top = (L->top - oldstack) + L->stack;
-  L->func = (L->func - oldstack) + L->stack;
   for (up = L->openupval; up != NULL; up = up->u.open.next)
     up->v = s2v((uplevel(up) - oldstack) + L->stack);
+  for (ci = L->ci; ci != NULL; ci = ci->previous) {
+    ci->top = (ci->top - oldstack) + L->stack;
+    ci->func = (ci->func - oldstack) + L->stack;
+  }
 }
 
 
@@ -203,11 +207,10 @@ void luaD_growstack (lua_State *L, int n) {
 
 
 static int stackinuse (lua_State *L) {
+  CallInfo *ci;
   StkId lim = L->top;
-  StkId func = L->func;
-  for (; func->stkci.previous != 0; func -= func->stkci.previous) {
-    if (lim < functop(func))
-      lim = functop(func);
+  for (ci = L->ci; ci != NULL; ci = ci->previous) {
+    if (lim < ci->top) lim = ci->top;
   }
   lua_assert(lim <= L->stack_last);
   return cast_int(lim - L->stack) + 1;  /* part of stack in use */
@@ -219,6 +222,10 @@ void luaD_shrinkstack (lua_State *L) {
   int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK;
   if (goodsize > LUAI_MAXSTACK)
     goodsize = LUAI_MAXSTACK;  /* respect stack limit */
+  if (L->stacksize > LUAI_MAXSTACK)  /* had been handling stack overflow? */
+    luaE_freeCI(L);  /* free all CIs (list grew because of an error) */
+  else
+    luaE_shrinkCI(L);  /* shrink list */
   /* if thread is currently not handling a stack overflow and its
      good size is smaller than current size, shrink its stack */
   if (inuse <= (LUAI_MAXSTACK - EXTRA_STACK) &&
@@ -245,46 +252,40 @@ void luaD_inctop (lua_State *L) {
 void luaD_hook (lua_State *L, int event, int line) {
   lua_Hook hook = L->hook;
   if (hook && L->allowhook) {  /* make sure there is a hook */
+    CallInfo *ci = L->ci;
     ptrdiff_t top = savestack(L, L->top);
-    int origframesize = L->func->stkci.framesize;
-    int tmpframesize;  /* frame size to run hook */
+    ptrdiff_t ci_top = savestack(L, ci->top);
     lua_Debug ar;
     ar.event = event;
     ar.currentline = line;
-    ar.i_actf = L->func - L->stack;
-    ar.i_actL = L;
+    ar.i_ci = ci;
     luaD_checkstack(L, LUA_MINSTACK);  /* ensure minimum stack size */
-    tmpframesize = L->top - L->func + LUA_MINSTACK;
-    if (tmpframesize > origframesize)  /* need to grow frame? */
-      L->func->stkci.framesize = tmpframesize;
-    lua_assert(functop(L->func) <= L->stack_last);
+    ci->top = L->top + LUA_MINSTACK;
+    lua_assert(ci->top <= L->stack_last);
     L->allowhook = 0;  /* cannot call hooks inside a hook */
-    callstatus(L->func) |= CIST_HOOKED;
+    ci->callstatus |= CIST_HOOKED;
     lua_unlock(L);
     (*hook)(L, &ar);
     lua_lock(L);
     lua_assert(!L->allowhook);
     L->allowhook = 1;
-    L->func->stkci.framesize = origframesize;
+    ci->top = restorestack(L, ci_top);
     L->top = restorestack(L, top);
-    callstatus(L->func) &= ~CIST_HOOKED;
+    ci->callstatus &= ~CIST_HOOKED;
   }
 }
 
 
-static void callhook (lua_State *L) {
+static void callhook (lua_State *L, CallInfo *ci) {
   int hook = LUA_HOOKCALL;
-  StkId func = L->func;
-  StkId previous = func - L->func->stkci.previous;
-  func->stkci.u.l.savedpc++;  /* hooks assume 'pc' is already incremented */
-  if (isLua(previous) &&
-      GET_OPCODE(*(previous->stkci.u.l.savedpc - 1)) == OP_TAILCALL) {
-    callstatus(L->func) |= CIST_TAIL;
+  ci->u.l.savedpc++;  /* hooks assume 'pc' is already incremented */
+  if (isLua(ci->previous) &&
+      GET_OPCODE(*(ci->previous->u.l.savedpc - 1)) == OP_TAILCALL) {
+    ci->callstatus |= CIST_TAIL;
     hook = LUA_HOOKTAILCALL;
   }
   luaD_hook(L, hook, -1);
-  func = L->func;  /* previous call can change stack */
-  func->stkci.u.l.savedpc--;  /* correct 'pc' */
+  ci->u.l.savedpc--;  /* correct 'pc' */
 }
 
 
@@ -355,25 +356,28 @@ static int moveresults (lua_State *L, StkId firstResult, StkId res,
 ** moves current number of results to proper place; returns 0 iff call
 ** wanted multiple (variable number of) results.
 */
-int luaD_poscall (lua_State *L, StkId firstResult, int nres) {
-  StkId res = L->func;  /* res == final position of 1st result */
-  int wanted = res->stkci.nresults;
+int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres) {
+  StkId res;
+  int wanted = ci->nresults;
   if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) {
     if (L->hookmask & LUA_MASKRET) {
       ptrdiff_t fr = savestack(L, firstResult);  /* hook may change stack */
       luaD_hook(L, LUA_HOOKRET, -1);
       firstResult = restorestack(L, fr);
-      res = L->func;
     }
-    /* 'oldpc' for caller function */
-    L->oldpc = (res - res->stkci.previous)->stkci.u.l.savedpc;
+    L->oldpc = ci->previous->u.l.savedpc;  /* 'oldpc' for caller function */
   }
-  L->func = res - res->stkci.previous;
+  res = ci->func;  /* res == final position of 1st result */
+  L->ci = ci->previous;  /* back to caller */
   /* move results to proper place */
   return moveresults(L, firstResult, res, nres, wanted);
 }
 
 
+
+#define next_ci(L) (L->ci = (L->ci->next ? L->ci->next : luaE_extendCI(L)))
+
+
 /*
 ** Prepares a function call: checks the stack, creates a new CallInfo
 ** entry, fills in the relevant information, calls hook if needed.
@@ -384,6 +388,7 @@ int luaD_poscall (lua_State *L, StkId firstResult, int nres) {
 int luaD_precall (lua_State *L, StkId func, int nresults) {
   lua_CFunction f;
   TValue *funcv = s2v(func);
+  CallInfo *ci;
   switch (ttype(funcv)) {
     case LUA_TCCL:  /* C closure */
       f = clCvalue(funcv)->f;
@@ -393,19 +398,19 @@ int luaD_precall (lua_State *L, StkId func, int nresults) {
      Cfunc: {
       int n;  /* number of returns */
       checkstackp(L, LUA_MINSTACK, func);  /* ensure minimum stack size */
-      func->stkci.nresults = nresults;
-      func->stkci.previous = func - L->func;
-      L->func = func;
-      setfunctop(func, L->top + LUA_MINSTACK);
-      lua_assert(functop(func) <= L->stack_last);
-      callstatus(func) = 0;
+      ci = next_ci(L);  /* now 'enter' new function */
+      ci->nresults = nresults;
+      ci->func = func;
+      ci->top = L->top + LUA_MINSTACK;
+      lua_assert(ci->top <= L->stack_last);
+      ci->callstatus = 0;
       if (L->hookmask & LUA_MASKCALL)
         luaD_hook(L, LUA_HOOKCALL, -1);
       lua_unlock(L);
       n = (*f)(L);  /* do the actual call */
       lua_lock(L);
       api_checknelems(L, n);
-      luaD_poscall(L, L->top - n, n);
+      luaD_poscall(L, ci, L->top - n, n);
       return 1;
     }
     case LUA_TLCL: {  /* Lua function: prepare its call */
@@ -417,16 +422,15 @@ int luaD_precall (lua_State *L, StkId func, int nresults) {
         setnilvalue(s2v(L->top++));  /* complete missing arguments */
       if (p->is_vararg)
         luaT_adjustvarargs(L, p, n);
-      func->stkci.nresults = nresults;
-      func->stkci.previous = func - L->func;
-      func->stkci.framesize = fsize + 1;  /* size includes function itself */
-      L->func = func;
-      L->top = func + 1 + fsize;
-      lua_assert(functop(func) <= L->stack_last);
-      func->stkci.u.l.savedpc = p->code;  /* starting point */
-      callstatus(func) = 0;
+      ci = next_ci(L);  /* now 'enter' new function */
+      ci->nresults = nresults;
+      ci->func = func;
+      L->top = ci->top = func + 1 + fsize;
+      lua_assert(ci->top <= L->stack_last);
+      ci->u.l.savedpc = p->code;  /* starting point */
+      ci->callstatus = CIST_LUA;
       if (L->hookmask & LUA_MASKCALL)
-        callhook(L);
+        callhook(L, ci);
       return 0;
     }
     default: {  /* not a function */
@@ -483,25 +487,24 @@ void luaD_callnoyield (lua_State *L, StkId func, int nResults) {
 ** continuation function.
 */
 static void finishCcall (lua_State *L, int status) {
-  StkId func = L->func;
+  CallInfo *ci = L->ci;
   int n;
   /* must have a continuation and must be able to call it */
-  lua_assert(func->stkci.u.c.k != NULL && L->nny == 0);
+  lua_assert(ci->u.c.k != NULL && L->nny == 0);
   /* error status can only happen in a protected call */
-  lua_assert((callstatus(func) & CIST_YPCALL) || status == LUA_YIELD);
-  if (callstatus(func) & CIST_YPCALL) {  /* was inside a pcall? */
-    callstatus(func) &= ~CIST_YPCALL;  /* continuation is also inside it */
-    L->errfunc = func->stkci.u.c.old_errfunc;  /* with same error function */
+  lua_assert((ci->callstatus & CIST_YPCALL) || status == LUA_YIELD);
+  if (ci->callstatus & CIST_YPCALL) {  /* was inside a pcall? */
+    ci->callstatus &= ~CIST_YPCALL;  /* continuation is also inside it */
+    L->errfunc = ci->u.c.old_errfunc;  /* with the same error function */
   }
   /* finish 'lua_callk'/'lua_pcall'; CIST_YPCALL and 'errfunc' already
      handled */
-  adjustresults(L, func->stkci.nresults);
+  adjustresults(L, ci->nresults);
   lua_unlock(L);
-  /* call continuation function */
-  n = (*func->stkci.u.c.k)(L, status, func->stkci.u.c.ctx);
+  n = (*ci->u.c.k)(L, status, ci->u.c.ctx);  /* call continuation function */
   lua_lock(L);
   api_checknelems(L, n);
-  luaD_poscall(L, L->top - n, n);  /* finish 'luaD_precall' */
+  luaD_poscall(L, ci, L->top - n, n);  /* finish 'luaD_precall' */
 }
 
 
@@ -516,8 +519,8 @@ static void finishCcall (lua_State *L, int status) {
 static void unroll (lua_State *L, void *ud) {
   if (ud != NULL)  /* error status? */
     finishCcall(L, *(int *)ud);  /* finish 'lua_pcallk' callee */
-  while (L->func != L->stack) {  /* something in the stack */
-    if (!isLua(L->func))  /* C function? */
+  while (L->ci != &L->base_ci) {  /* something in the stack */
+    if (!isLua(L->ci))  /* C function? */
       finishCcall(L, LUA_YIELD);  /* complete its execution */
     else {  /* Lua function */
       luaV_finishOp(L);  /* finish interrupted instruction */
@@ -531,13 +534,11 @@ static void unroll (lua_State *L, void *ud) {
 ** Try to find a suspended protected call (a "recover point") for the
 ** given thread.
 */
-static StkId findpcall (lua_State *L) {
-  StkId func;
-  for (func = L->func;
-       func->stkci.previous != 0;
-       func -= func->stkci.previous) {
-    if (callstatus(func) & CIST_YPCALL)
-      return func;
+static CallInfo *findpcall (lua_State *L) {
+  CallInfo *ci;
+  for (ci = L->ci; ci != NULL; ci = ci->previous) {  /* search for a pcall */
+    if (ci->callstatus & CIST_YPCALL)
+      return ci;
   }
   return NULL;  /* no pending pcall */
 }
@@ -550,17 +551,17 @@ static StkId findpcall (lua_State *L) {
 */
 static int recover (lua_State *L, int status) {
   StkId oldtop;
-  StkId recf = findpcall(L);
-  if (recf == NULL) return 0;  /* no recovery point */
+  CallInfo *ci = findpcall(L);
+  if (ci == NULL) return 0;  /* no recovery point */
   /* "finish" luaD_pcall */
-  oldtop = recf + recf->stkci.u2.funcidx;
+  oldtop = restorestack(L, ci->u2.funcidx);
   luaF_close(L, oldtop);
   seterrorobj(L, status, oldtop);
-  L->func = recf;
-  L->allowhook = getoah(callstatus(recf));  /* restore original 'allowhook' */
+  L->ci = ci;
+  L->allowhook = getoah(ci->callstatus);  /* restore original 'allowhook' */
   L->nny = 0;  /* should be zero to be yieldable */
   luaD_shrinkstack(L);
-  L->errfunc = recf->stkci.u.c.old_errfunc;
+  L->errfunc = ci->u.c.old_errfunc;
   return 1;  /* continue running the coroutine */
 }
 
@@ -589,7 +590,7 @@ static int resume_error (lua_State *L, const char *msg, int narg) {
 static void resume (lua_State *L, void *ud) {
   int n = *(cast(int*, ud));  /* number of arguments */
   StkId firstArg = L->top - n;  /* first argument */
-  StkId func = L->func;
+  CallInfo *ci = L->ci;
   if (L->status == LUA_OK) {  /* starting a coroutine? */
     if (!luaD_precall(L, firstArg - 1, LUA_MULTRET))  /* Lua function? */
       luaV_execute(L);  /* call it */
@@ -597,18 +598,17 @@ static void resume (lua_State *L, void *ud) {
   else {  /* resuming from previous yield */
     lua_assert(L->status == LUA_YIELD);
     L->status = LUA_OK;  /* mark that it is running (again) */
-    if (isLua(func))  /* yielded inside a hook? */
+    if (isLua(ci))  /* yielded inside a hook? */
       luaV_execute(L);  /* just continue running Lua code */
     else {  /* 'common' yield */
-      if (func->stkci.u.c.k != NULL) {  /* does it have a continuation? */
+      if (ci->u.c.k != NULL) {  /* does it have a continuation function? */
         lua_unlock(L);
-        /* call continuation */
-        n = (*func->stkci.u.c.k)(L, LUA_YIELD, func->stkci.u.c.ctx);
+        n = (*ci->u.c.k)(L, LUA_YIELD, ci->u.c.ctx); /* call continuation */
         lua_lock(L);
         api_checknelems(L, n);
         firstArg = L->top - n;  /* yield results come from continuation */
       }
-      luaD_poscall(L, firstArg, n);  /* finish 'luaD_precall' */
+      luaD_poscall(L, ci, firstArg, n);  /* finish 'luaD_precall' */
     }
     unroll(L, NULL);  /* run continuation */
   }
@@ -621,7 +621,7 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
   unsigned short oldnny = L->nny;  /* save "number of non-yieldable" calls */
   lua_lock(L);
   if (L->status == LUA_OK) {  /* may be starting a coroutine */
-    if (L->func != L->stack)  /* not in base level? */
+    if (L->ci != &L->base_ci)  /* not in base level? */
       return resume_error(L, "cannot resume non-suspended coroutine", nargs);
   }
   else if (L->status != LUA_YIELD)
@@ -643,12 +643,12 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
     if (errorstatus(status)) {  /* unrecoverable error? */
       L->status = cast_byte(status);  /* mark thread as 'dead' */
       seterrorobj(L, status, L->top);  /* push error message */
-      L->func->stkci.framesize = L->top - L->func;
+      L->ci->top = L->top;
     }
     else lua_assert(status == L->status);  /* normal end or yield */
   }
-  *nresults = (status == LUA_YIELD) ? L->func->stkci.u2.nyield
-                                    : L->top - (L->func + 1);
+  *nresults = (status == LUA_YIELD) ? L->ci->u2.nyield
+                                    : L->top - (L->ci->func + 1);
   L->nny = oldnny;  /* restore 'nny' */
   L->nCcalls--;
   lua_assert(L->nCcalls == ((from) ? from->nCcalls : 0));
@@ -664,7 +664,7 @@ LUA_API int lua_isyieldable (lua_State *L) {
 
 LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx,
                         lua_KFunction k) {
-  StkId func = L->func;
+  CallInfo *ci = L->ci;
   luai_userstateyield(L, nresults);
   lua_lock(L);
   api_checknelems(L, nresults);
@@ -675,17 +675,17 @@ LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx,
       luaG_runerror(L, "attempt to yield from outside a coroutine");
   }
   L->status = LUA_YIELD;
-  if (isLua(func)) {  /* inside a hook? */
+  if (isLua(ci)) {  /* inside a hook? */
     api_check(L, k == NULL, "hooks cannot continue after yielding");
-    func->stkci.u2.nyield = 0;  /* no results */
+    ci->u2.nyield = 0;  /* no results */
   }
   else {
-    if ((func->stkci.u.c.k = k) != NULL)  /* is there a continuation? */
-      func->stkci.u.c.ctx = ctx;  /* save context */
-    func->stkci.u2.nyield = nresults;  /* save number of results */
+    if ((ci->u.c.k = k) != NULL)  /* is there a continuation? */
+      ci->u.c.ctx = ctx;  /* save context */
+    ci->u2.nyield = nresults;  /* save number of results */
     luaD_throw(L, LUA_YIELD);
   }
-  lua_assert(callstatus(func) & CIST_HOOKED);  /* must be inside a hook */
+  lua_assert(ci->callstatus & CIST_HOOKED);  /* must be inside a hook */
   lua_unlock(L);
   return 0;  /* return to 'luaD_hook' */
 }
@@ -694,7 +694,7 @@ LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx,
 int luaD_pcall (lua_State *L, Pfunc func, void *u,
                 ptrdiff_t old_top, ptrdiff_t ef) {
   int status;
-  ptrdiff_t oldfunc = savestack(L, L->func);
+  CallInfo *old_ci = L->ci;
   lu_byte old_allowhooks = L->allowhook;
   unsigned short old_nny = L->nny;
   ptrdiff_t old_errfunc = L->errfunc;
@@ -704,7 +704,7 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u,
     StkId oldtop = restorestack(L, old_top);
     luaF_close(L, oldtop);  /* close possible pending closures */
     seterrorobj(L, status, oldtop);
-    L->func = restorestack(L, oldfunc);
+    L->ci = old_ci;
     L->allowhook = old_allowhooks;
     L->nny = old_nny;
     luaD_shrinkstack(L);

+ 3 - 2
ldo.h

@@ -1,5 +1,5 @@
 /*
-** $Id: ldo.h,v 2.31 2017/06/29 15:06:44 roberto Exp roberto $
+** $Id: ldo.h,v 2.31 2017/06/29 15:06:44 roberto Exp $
 ** Stack and Call structure of Lua
 ** See Copyright Notice in lua.h
 */
@@ -52,7 +52,8 @@ LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults);
 LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults);
 LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u,
                                         ptrdiff_t oldtop, ptrdiff_t ef);
-LUAI_FUNC int luaD_poscall (lua_State *L, StkId firstResult, int nres);
+LUAI_FUNC int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult,
+                                          int nres);
 LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize);
 LUAI_FUNC void luaD_growstack (lua_State *L, int n);
 LUAI_FUNC void luaD_shrinkstack (lua_State *L);

+ 3 - 3
lgc.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lgc.c,v 2.236 2017/10/31 15:29:28 roberto Exp roberto $
+** $Id: lgc.c,v 2.236 2017/10/31 15:29:28 roberto Exp $
 ** Garbage Collector
 ** See Copyright Notice in lua.h
 */
@@ -866,9 +866,9 @@ static void GCTM (lua_State *L, int propagateerrors) {
     setobj2s(L, L->top, tm);  /* push finalizer... */
     setobj2s(L, L->top + 1, &v);  /* ... and its argument */
     L->top += 2;  /* and (next line) call the finalizer */
-    callstatus(L->func) |= CIST_FIN;  /* will run a finalizer */
+    L->ci->callstatus |= CIST_FIN;  /* will run a finalizer */
     status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0);
-    callstatus(L->func) &= ~CIST_FIN;  /* not running a finalizer anymore */
+    L->ci->callstatus &= ~CIST_FIN;  /* not running a finalizer anymore */
     L->allowhook = oldah;  /* restore hooks */
     g->gcrunning = running;  /* restore state */
     if (status != LUA_OK && propagateerrors) {  /* error while running __gc? */

+ 1 - 31
lobject.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lobject.h,v 2.128 2017/11/03 17:22:54 roberto Exp roberto $
+** $Id: lobject.h,v 2.125 2017/06/29 15:06:44 roberto Exp $
 ** Type definitions for Lua objects
 ** See Copyright Notice in lua.h
 */
@@ -311,39 +311,9 @@ typedef struct TValue {
 
 typedef union StackValue {
   TValue val;
-  struct {
-    TValuefields;
-    lu_byte callstatus_;
-    char nresults;  /* expected number of results from this function */
-    union {
-      unsigned char funcidx;  /* called-function index */
-      unsigned char nyield;  /* number of values yielded */
-    } u2;
-    unsigned short previous;  /* difference to previous 'func' */
-    unsigned short framesize;  /* stack space available for this function */
-    union {
-      struct {  /* only for Lua functions */
-        const Instruction *savedpc;
-      } l;
-      struct {  /* only for C functions */
-        lua_KFunction k;  /* continuation in case of yields */
-        int old_errfunc;
-        int ctx;  /* context info. in case of yields */
-      } c;
-    } u;
-  } stkci;
 } StackValue;
 
 
-#define callstatus(ar)	((ar)->stkci.callstatus_)
-
-/* top of a function (first element after its frame) */
-#define functop(func)	((func) + (func)->stkci.framesize)
-
-/* set top of a function to a specific value */
-#define setfunctop(func,v)	((func)->stkci.framesize = (v) - (func))
-
-
 typedef StackValue *StkId;  /* index to stack elements */
 
 /* convert a 'StackValue' to a 'TValue' */

+ 55 - 8
lstate.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lstate.c,v 2.144 2017/11/03 12:12:30 roberto Exp roberto $
+** $Id: lstate.c,v 2.143 2017/10/31 17:54:35 roberto Exp $
 ** Global State
 ** See Copyright Notice in lua.h
 */
@@ -97,8 +97,51 @@ void luaE_setdebt (global_State *g, l_mem debt) {
 }
 
 
+CallInfo *luaE_extendCI (lua_State *L) {
+  CallInfo *ci = luaM_new(L, CallInfo);
+  lua_assert(L->ci->next == NULL);
+  L->ci->next = ci;
+  ci->previous = L->ci;
+  ci->next = NULL;
+  L->nci++;
+  return ci;
+}
+
+
+/*
+** free all CallInfo structures not in use by a thread
+*/
+void luaE_freeCI (lua_State *L) {
+  CallInfo *ci = L->ci;
+  CallInfo *next = ci->next;
+  ci->next = NULL;
+  while ((ci = next) != NULL) {
+    next = ci->next;
+    luaM_free(L, ci);
+    L->nci--;
+  }
+}
+
+
+/*
+** free half of the CallInfo structures not in use by a thread
+*/
+void luaE_shrinkCI (lua_State *L) {
+  CallInfo *ci = L->ci;
+  CallInfo *next2;  /* next's next */
+  /* while there are two nexts */
+  while (ci->next != NULL && (next2 = ci->next->next) != NULL) {
+    luaM_free(L, ci->next);  /* free next */
+    L->nci--;
+    ci->next = next2;  /* remove 'next' from the list */
+    next2->previous = ci;
+    ci = next2;  /* keep next's next */
+  }
+}
+
+
 static void stack_init (lua_State *L1, lua_State *L) {
-  int i;
+  int i; CallInfo *ci;
   /* initialize stack array */
   L1->stack = luaM_newvector(L, BASIC_STACK_SIZE, StackValue);
   L1->stacksize = BASIC_STACK_SIZE;
@@ -106,19 +149,23 @@ static void stack_init (lua_State *L1, lua_State *L) {
     setnilvalue(s2v(L1->stack + i));  /* erase new stack */
   L1->top = L1->stack;
   L1->stack_last = L1->stack + L1->stacksize - EXTRA_STACK;
-  /* initialize first 'function' */
-  L1->func = L1->stack;
-  L1->func->stkci.previous = 0;  /* end of linked list */
-  L1->func->stkci.framesize = LUA_MINSTACK + 1;
-  callstatus(L1->func) = 0;
+  /* initialize first ci */
+  ci = &L1->base_ci;
+  ci->next = ci->previous = NULL;
+  ci->callstatus = 0;
+  ci->func = L1->top;
   setnilvalue(s2v(L1->top));  /* 'function' entry for this 'ci' */
   L1->top++;
+  ci->top = L1->top + LUA_MINSTACK;
+  L1->ci = ci;
 }
 
 
 static void freestack (lua_State *L) {
   if (L->stack == NULL)
     return;  /* stack not completely built yet */
+  L->ci = &L->base_ci;  /* free the entire 'ci' list */
+  luaE_freeCI(L);
   lua_assert(L->nci == 0);
   luaM_freearray(L, L->stack, L->stacksize);  /* free stack array */
 }
@@ -168,7 +215,7 @@ static void f_luaopen (lua_State *L, void *ud) {
 static void preinit_thread (lua_State *L, global_State *g) {
   G(L) = g;
   L->stack = NULL;
-  L->func = NULL;
+  L->ci = NULL;
   L->nci = 0;
   L->stacksize = 0;
   L->twups = L;  /* thread has no upvalues */

+ 40 - 10
lstate.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lstate.h,v 2.148 2017/11/03 17:22:54 roberto Exp roberto $
+** $Id: lstate.h,v 2.146 2017/11/02 11:28:56 roberto Exp $
 ** Global State
 ** See Copyright Notice in lua.h
 */
@@ -81,21 +81,47 @@ typedef struct stringtable {
 } stringtable;
 
 
+/*
+** Information about a call.
+*/
+typedef struct CallInfo {
+  StkId func;  /* function index in the stack */
+  StkId	top;  /* top for this function */
+  struct CallInfo *previous, *next;  /* dynamic call link */
+  union {
+    struct {  /* only for Lua functions */
+      const Instruction *savedpc;
+    } l;
+    struct {  /* only for C functions */
+      lua_KFunction k;  /* continuation in case of yields */
+      ptrdiff_t old_errfunc;
+      lua_KContext ctx;  /* context info. in case of yields */
+    } c;
+  } u;
+  union {
+    int funcidx;  /* called-function index */
+    int nyield;  /* number of values yielded */
+  } u2;
+  short nresults;  /* expected number of results from this function */
+  unsigned short callstatus;
+} CallInfo;
+
 
 /*
 ** Bits in CallInfo status
 */
 #define CIST_OAH	(1<<0)	/* original value of 'allowhook' */
-#define CIST_HOOKED	(1<<1)	/* call is running a debug hook */
-#define CIST_FRESH	(1<<2)	/* call is running on a fresh invocation
+#define CIST_LUA	(1<<1)	/* call is running a Lua function */
+#define CIST_HOOKED	(1<<2)	/* call is running a debug hook */
+#define CIST_FRESH	(1<<3)	/* call is running on a fresh invocation
                                    of luaV_execute */
-#define CIST_YPCALL	(1<<3)	/* call is a yieldable protected call */
-#define CIST_TAIL	(1<<4)	/* call was tail called */
-#define CIST_HOOKYIELD	(1<<5)	/* last hook called yielded */
-#define CIST_LEQ	(1<<6)  /* using __lt for __le */
-#define CIST_FIN	(1<<7)  /* call is running a finalizer */
+#define CIST_YPCALL	(1<<4)	/* call is a yieldable protected call */
+#define CIST_TAIL	(1<<5)	/* call was tail called */
+#define CIST_HOOKYIELD	(1<<6)	/* last hook called yielded */
+#define CIST_LEQ	(1<<7)  /* using __lt for __le */
+#define CIST_FIN	(1<<8)  /* call is running a finalizer */
 
-#define isLua(func)	isLfunction(s2v(func))
+#define isLua(ci)	((ci)->callstatus & CIST_LUA)
 
 /* assume that CIST_OAH has offset 0 and that 'v' is strictly 0/1 */
 #define setoah(st,v)	((st) = ((st) & ~CIST_OAH) | (v))
@@ -162,7 +188,7 @@ struct lua_State {
   lu_byte status;
   StkId top;  /* first free slot in the stack */
   global_State *l_G;
-  StkId func;  /* current function */
+  CallInfo *ci;  /* call info for current function */
   const Instruction *oldpc;  /* last pc traced */
   StkId stack_last;  /* last free slot in the stack */
   StkId stack;  /* stack base */
@@ -170,6 +196,7 @@ struct lua_State {
   GCObject *gclist;
   struct lua_State *twups;  /* list of threads with open upvalues */
   struct lua_longjmp *errorJmp;  /* current error recover point */
+  CallInfo base_ci;  /* CallInfo for first level (C calling Lua) */
   volatile lua_Hook hook;
   ptrdiff_t errfunc;  /* current error handling function (stack index) */
   int stacksize;
@@ -225,6 +252,9 @@ union GCUnion {
 
 LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt);
 LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);
+LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L);
+LUAI_FUNC void luaE_freeCI (lua_State *L);
+LUAI_FUNC void luaE_shrinkCI (lua_State *L);
 
 
 #endif

+ 12 - 11
ltests.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ltests.c,v 2.228 2017/11/03 12:12:30 roberto Exp roberto $
+** $Id: ltests.c,v 2.227 2017/11/02 11:28:56 roberto Exp $
 ** Internal Module for Debugging of the Lua Implementation
 ** See Copyright Notice in lua.h
 */
@@ -46,7 +46,7 @@ void *l_Trick = 0;
 int islocked = 0;
 
 
-#define obj_at(L,k)	s2v(L->func + (k))
+#define obj_at(L,k)	s2v(L->ci->func + (k))
 
 
 static int runC (lua_State *L, lua_State *L1, const char *pc);
@@ -309,27 +309,28 @@ static void checkLclosure (global_State *g, LClosure *cl) {
 }
 
 
-static int lua_checkpc (StkId func) {
-  if (!isLua(func)) return 1;
+static int lua_checkpc (CallInfo *ci) {
+  if (!isLua(ci)) return 1;
   else {
-    Proto *p = clLvalue(s2v(func))->p;
-    return p->code <= func->stkci.u.l.savedpc &&
-           func->stkci.u.l.savedpc <= p->code + p->sizecode;
+    StkId f = ci->func;
+    Proto *p = clLvalue(s2v(f))->p;
+    return p->code <= ci->u.l.savedpc &&
+           ci->u.l.savedpc <= p->code + p->sizecode;
   }
 }
 
 
 static void checkstack (global_State *g, lua_State *L1) {
   StkId o;
+  CallInfo *ci;
   UpVal *uv;
   lua_assert(!isdead(g, L1));
   for (uv = L1->openupval; uv != NULL; uv = uv->u.open.next)
     lua_assert(upisopen(uv));  /* must be open */
-  for (o = L1->func; o->stkci.previous != 0; o -= o->stkci.previous) {
-    lua_assert(functop(o) <= L1->stack_last);
-    lua_assert(lua_checkpc(o));
+  for (ci = L1->ci; ci != NULL; ci = ci->previous) {
+    lua_assert(ci->top <= L1->stack_last);
+    lua_assert(lua_checkpc(ci));
   }
-  lua_assert(o == L1->stack);
   if (L1->stack) {  /* complete thread? */
     for (o = L1->stack; o < L1->stack_last + EXTRA_STACK; o++)
       checkliveness(L1, s2v(o));  /* entire stack must have valid values */

+ 3 - 3
ltm.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ltm.c,v 2.45 2017/10/04 15:49:05 roberto Exp roberto $
+** $Id: ltm.c,v 2.45 2017/10/04 15:49:05 roberto Exp $
 ** Tag methods
 ** See Copyright Notice in lua.h
 */
@@ -108,7 +108,7 @@ void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
   setobj2s(L, func + 3, p3);  /* 3rd argument */
   L->top += 4;
   /* metamethod may yield only when called from Lua code */
-  if (isLua(L->func))
+  if (isLua(L->ci))
     luaD_call(L, func, 0);
   else
     luaD_callnoyield(L, func, 0);
@@ -124,7 +124,7 @@ void luaT_callTMres (lua_State *L, const TValue *f, const TValue *p1,
   setobj2s(L, func + 2, p2);  /* 2nd argument */
   L->top += 3;
   /* metamethod may yield only when called from Lua code */
-  if (isLua(L->func))
+  if (isLua(L->ci))
     luaD_call(L, func, 1);
   else
     luaD_callnoyield(L, func, 1);

+ 2 - 3
lua.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lua.h,v 1.337 2017/11/02 11:28:56 roberto Exp roberto $
+** $Id: lua.h,v 1.337 2017/11/02 11:28:56 roberto Exp $
 ** Lua - A Scripting Language
 ** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
 ** See Copyright Notice at the end of this file
@@ -456,8 +456,7 @@ struct lua_Debug {
   char istailcall;	/* (t) */
   char short_src[LUA_IDSIZE]; /* (S) */
   /* private part */
-  int i_actf;  /* active function */
-  lua_State *i_actL;  /* where active function is active */
+  struct CallInfo *i_ci;  /* active function */
 };
 
 /* }====================================================================== */

+ 66 - 67
lvm.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lvm.c,v 2.304 2017/11/03 19:33:22 roberto Exp roberto $
+** $Id: lvm.c,v 2.301 2017/11/01 18:20:48 roberto Exp $
 ** Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -390,9 +390,9 @@ int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) {
   else if ((res = luaT_callorderTM(L, l, r, TM_LE)) >= 0)  /* try 'le' */
     return res;
   else {  /* try 'lt': */
-    callstatus(L->func) |= CIST_LEQ;  /* mark it is doing 'lt' for 'le' */
+    L->ci->callstatus |= CIST_LEQ;  /* mark it is doing 'lt' for 'le' */
     res = luaT_callorderTM(L, r, l, TM_LT);
-    callstatus(L->func) ^= CIST_LEQ;  /* clear mark */
+    L->ci->callstatus ^= CIST_LEQ;  /* clear mark */
     if (res < 0)
       luaG_ordererror(L, l, r);
     return !res;  /* result is negated */
@@ -654,14 +654,13 @@ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
 }
 
 
-#define basepc(base)	((base - 1)->stkci.u.l.savedpc)
-
 /*
 ** finish execution of an opcode interrupted by an yield
 */
 void luaV_finishOp (lua_State *L) {
-  StkId base = L->func + 1;
-  Instruction inst = *(basepc(base) - 1);  /* interrupted instruction */
+  CallInfo *ci = L->ci;
+  StkId base = ci->func + 1;
+  Instruction inst = *(ci->u.l.savedpc - 1);  /* interrupted instruction */
   OpCode op = GET_OPCODE(inst);
   switch (op) {  /* finish its execution */
     case OP_ADDI: case OP_SUBI:
@@ -680,14 +679,14 @@ void luaV_finishOp (lua_State *L) {
     case OP_LE: case OP_LT: case OP_EQ: {
       int res = !l_isfalse(s2v(L->top - 1));
       L->top--;
-      if (callstatus(base - 1) & CIST_LEQ) {  /* "<=" using "<" ? */
+      if (ci->callstatus & CIST_LEQ) {  /* "<=" using "<" instead? */
         lua_assert(op == OP_LE);
-        callstatus(base - 1) ^= CIST_LEQ;  /* clear mark */
+        ci->callstatus ^= CIST_LEQ;  /* clear mark */
         res = !res;  /* negate result */
       }
-      lua_assert(GET_OPCODE(*basepc(base)) == OP_JMP);
+      lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP);
       if (res != GETARG_A(inst))  /* condition failed? */
-        basepc(base)++;  /* skip jump instruction */
+        ci->u.l.savedpc++;  /* skip jump instruction */
       break;
     }
     case OP_CONCAT: {
@@ -700,18 +699,18 @@ void luaV_finishOp (lua_State *L) {
         luaV_concat(L, total);  /* concat them (may yield again) */
       }
       /* move final result to final position */
-      setobjs2s(L, L->func + 1 + GETARG_A(inst), L->top - 1);
-      L->top = functop(base - 1);  /* restore top */
+      setobjs2s(L, ci->func + 1 + GETARG_A(inst), L->top - 1);
+      L->top = ci->top;  /* restore top */
       break;
     }
     case OP_TFORCALL: {
-      lua_assert(GET_OPCODE(*basepc(base)) == OP_TFORLOOP);
-      L->top = functop(base - 1);  /* correct top */
+      lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_TFORLOOP);
+      L->top = ci->top;  /* correct top */
       break;
     }
     case OP_CALL: {
       if (GETARG_C(inst) - 1 >= 0)  /* nresults >= 0? */
-        L->top = functop(base - 1);  /* adjust results */
+        L->top = ci->top;  /* adjust results */
       break;
     }
     case OP_TAILCALL: case OP_SETTABUP: case OP_SETTABLE:
@@ -754,33 +753,31 @@ void luaV_finishOp (lua_State *L) {
 ** Execute a jump instruction. The 'updatemask' allows signals to stop
 ** tight loops. (Without it, the local copy of 'mask' could never change.)
 */
-#define dojump(i,e)	{ pc += GETARG_sBx(i) + e; updatemask(L); }
+#define dojump(ci,i,e)	{ pc += GETARG_sBx(i) + e; updatemask(L); }
 
 
 /* for test instructions, execute the jump instruction that follows it */
-#define donextjump()	{ i = *pc; dojump(i, 1); }
+#define donextjump(ci)	{ i = *pc; dojump(ci, i, 1); }
 
 /*
 ** Whenever code can raise errors (including memory errors), the global
 ** 'pc' must be correct to report occasional errors.
 */
-#define savepc(base)	(basepc(base) = pc)
-
+#define savepc(L)	(ci->u.l.savedpc = pc)
 
-/* update internal copies to its correct values */
-#define updatestate()	(base = L->func + 1, updatemask(L))
 
 /*
 ** Protect code that, in general, can raise errors, reallocate the
 ** stack, and change the hooks.
 */
-#define Protect(code)	{ savepc(base); {code;}; updatestate(); }
+#define Protect(code)  \
+  { savepc(L); {code;}; base = ci->func + 1; updatemask(L); }
 
 
 #define checkGC(L,c)  \
-  { luaC_condGC(L, L->top = (c),  /* limit of live values */ \
-    {updatestate(); L->top = functop(base - 1);});  /* restore top */ \
-    luai_threadyield(L); }
+	{ luaC_condGC(L, L->top = (c),  /* limit of live values */ \
+                         Protect(L->top = ci->top));  /* restore top */ \
+           luai_threadyield(L); }
 
 
 /* fetch an instruction and prepare its execution */
@@ -796,23 +793,26 @@ void luaV_finishOp (lua_State *L) {
 
 
 void luaV_execute (lua_State *L) {
+  CallInfo *ci = L->ci;
   LClosure *cl;
   TValue *k;
-  StkId base = L->func + 1;  /* local copy of 'L->func + 1' */
+  StkId base;  /* local copy of 'ci->func + 1' */
   int mask;  /* local copy of 'L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)' */
-  const Instruction *pc;  /* local copy of 'basepc(base)' */
-  callstatus(base - 1) |= CIST_FRESH;  /* fresh invocation of 'luaV_execute" */
+  const Instruction *pc;  /* local copy of 'ci->u.l.savedpc' */
+  ci->callstatus |= CIST_FRESH;  /* fresh invocation of 'luaV_execute" */
  newframe:  /* reentry point when frame changes (call/return) */
-  cl = clLvalue(s2v(L->func));  /* local reference to function's closure */
+  lua_assert(ci == L->ci);
+  cl = clLvalue(s2v(ci->func));  /* local reference to function's closure */
   k = cl->p->k;  /* local reference to function's constant table */
   updatemask(L);
-  pc = basepc(base);
+  base = ci->func + 1;
+  pc = ci->u.l.savedpc;
   /* main loop of interpreter */
   for (;;) {
     Instruction i;
     StkId ra;
     vmfetch();
-    lua_assert(base == L->func + 1);
+    lua_assert(base == ci->func + 1);
     lua_assert(base <= L->top && L->top < L->stack + L->stacksize);
     vmdispatch (GET_OPCODE(i)) {
       vmcase(OP_MOVE) {
@@ -970,7 +970,7 @@ void luaV_execute (lua_State *L) {
         int b = GETARG_B(i);
         int c = GETARG_C(i);
         Table *t;
-        savepc(base);  /* in case of allocation errors */
+        savepc(L);  /* in case of allocation errors */
         t = luaH_new(L);
         sethvalue2s(L, ra, t);
         if (b != 0 || c != 0)
@@ -1276,7 +1276,7 @@ void luaV_execute (lua_State *L) {
         rb = base + b;
         setobjs2s(L, ra, rb);
         checkGC(L, (ra >= rb ? ra + 1 : rb));
-        L->top = functop(base - 1);  /* restore top */
+        L->top = ci->top;  /* restore top */
         vmbreak;
       }
       vmcase(OP_CLOSE) {
@@ -1284,7 +1284,7 @@ void luaV_execute (lua_State *L) {
         vmbreak;
       }
       vmcase(OP_JMP) {
-        dojump(i, 0);
+        dojump(ci, i, 0);
         vmbreak;
       }
       vmcase(OP_EQ) {
@@ -1294,7 +1294,7 @@ void luaV_execute (lua_State *L) {
           if (luaV_equalobj(L, rb, rc) != GETARG_A(i))
             pc++;
           else
-            donextjump();
+            donextjump(ci);
         )
         vmbreak;
       }
@@ -1310,7 +1310,7 @@ void luaV_execute (lua_State *L) {
         if (res != GETARG_A(i))
           pc++;
         else
-          donextjump();
+          donextjump(ci);
         vmbreak;
       }
       vmcase(OP_LE) {
@@ -1325,14 +1325,14 @@ void luaV_execute (lua_State *L) {
         if (res != GETARG_A(i))
           pc++;
         else
-          donextjump();
+          donextjump(ci);
         vmbreak;
       }
       vmcase(OP_TEST) {
         if (GETARG_C(i) ? l_isfalse(s2v(ra)) : !l_isfalse(s2v(ra)))
             pc++;
           else
-          donextjump();
+          donextjump(ci);
         vmbreak;
       }
       vmcase(OP_TESTSET) {
@@ -1341,7 +1341,7 @@ void luaV_execute (lua_State *L) {
           pc++;
         else {
           setobj2s(L, ra, rb);
-          donextjump();
+          donextjump(ci);
         }
         vmbreak;
       }
@@ -1355,11 +1355,11 @@ void luaV_execute (lua_State *L) {
         Protect(isC = luaD_precall(L, ra, nresults));
         if (isC) {  /* C function? */
           if (nresults >= 0)  /* fixed number of results? */
-            L->top = functop(base - 1);  /* correct top */
+            L->top = ci->top;  /* correct top */
           /* else leave top for next instruction */
         }
         else {  /* Lua function */
-          base = L->func + 1;
+          ci = L->ci;
           goto newframe;  /* restart luaV_execute over new Lua function */
         }
         vmbreak;
@@ -1368,14 +1368,16 @@ void luaV_execute (lua_State *L) {
         int b = GETARG_B(i);
         if (b != 0) L->top = ra+b;  /* else previous instruction set top */
         lua_assert(GETARG_C(i) - 1 == LUA_MULTRET);
-        savepc(base);
+        savepc(L);
         if (luaD_precall(L, ra, LUA_MULTRET)) {  /* C function? */
-          updatestate();  /* update 'base' */
+          Protect((void)0);  /* update 'base' */
         }
         else {
           /* tail call: put called frame (n) in place of caller one (o) */
-          StkId nfunc = L->func;  /* called function */
-          StkId ofunc = nfunc - nfunc->stkci.previous;  /* caller function */
+          CallInfo *nci = L->ci;  /* called frame (new) */
+          CallInfo *oci = nci->previous;  /* caller frame (old) */
+          StkId nfunc = nci->func;  /* called function */
+          StkId ofunc = oci->func;  /* caller function */
           /* last stack slot filled by 'precall' */
           StkId lim = nfunc + 1 + getproto(s2v(nfunc))->numparams;
           int aux;
@@ -1384,13 +1386,11 @@ void luaV_execute (lua_State *L) {
           /* move new frame into old one */
           for (aux = 0; nfunc + aux < lim; aux++)
             setobjs2s(L, ofunc + aux, nfunc + aux);
-          ofunc->stkci.framesize = L->top - nfunc;
-          L->top = functop(ofunc);  /* correct top */
-          ofunc->stkci.u.l.savedpc = nfunc->stkci.u.l.savedpc;
-          callstatus(ofunc) |= CIST_TAIL;  /* function was tail called */
-          base = ofunc + 1;
-          L->func = ofunc;
-          lua_assert(L->top == base + getproto(s2v(ofunc))->maxstacksize);
+          oci->top = L->top = ofunc + (L->top - nfunc);  /* correct top */
+          oci->u.l.savedpc = nci->u.l.savedpc;
+          oci->callstatus |= CIST_TAIL;  /* function was tail called */
+          ci = L->ci = oci;  /* remove new frame */
+          lua_assert(L->top == ofunc + 1 + getproto(s2v(ofunc))->maxstacksize);
           goto newframe;  /* restart luaV_execute over new Lua function */
         }
         vmbreak;
@@ -1398,16 +1398,16 @@ void luaV_execute (lua_State *L) {
       vmcase(OP_RETURN) {
         int b = GETARG_B(i);
         if (cl->p->sizep > 0) luaF_close(L, base);
-        savepc(base);
-        b = luaD_poscall(L, ra, (b != 0 ? b - 1 : cast_int(L->top - ra)));
-        if (callstatus(base - 1) & CIST_FRESH)  /* local 'base' still from callee */
+        savepc(L);
+        b = luaD_poscall(L, ci, ra, (b != 0 ? b - 1 : cast_int(L->top - ra)));
+        if (ci->callstatus & CIST_FRESH)  /* local 'ci' still from callee */
           return;  /* external invocation: return */
         else {  /* invocation via reentry: continue execution */
-          base = L->func + 1;
-          if (b) L->top = functop(base - 1);
-          lua_assert(isLua(base - 1));
-          lua_assert(GET_OPCODE(*(basepc(base) - 1)) == OP_CALL);
-          goto newframe;  /* restart luaV_execute over previous Lua function */
+          ci = L->ci;
+          if (b) L->top = ci->top;
+          lua_assert(isLua(ci));
+          lua_assert(GET_OPCODE(*((ci)->u.l.savedpc - 1)) == OP_CALL);
+          goto newframe;  /* restart luaV_execute over new Lua function */
         }
       }
       vmcase(OP_FORLOOP) {
@@ -1451,7 +1451,7 @@ void luaV_execute (lua_State *L) {
         }
         else {  /* try making all values floats */
           lua_Number ninit; lua_Number nlimit; lua_Number nstep;
-          savepc(base);  /* in case of errors */
+          savepc(L);  /* in case of errors */
           if (!tonumber(plimit, &nlimit))
             luaG_runerror(L, "'for' limit must be a number");
           setfltvalue(plimit, nlimit);
@@ -1472,7 +1472,7 @@ void luaV_execute (lua_State *L) {
         setobjs2s(L, cb, ra);
         L->top = cb + 3;  /* func. + 2 args (state and index) */
         Protect(luaD_call(L, cb, GETARG_C(i)));
-        L->top = functop(base - 1);
+        L->top = ci->top;
         i = *(pc++);  /* go to next instruction */
         ra = RA(i);
         lua_assert(GET_OPCODE(i) == OP_TFORLOOP);
@@ -1497,7 +1497,7 @@ void luaV_execute (lua_State *L) {
         }
         h = hvalue(s2v(ra));
         last = ((c-1)*LFIELDS_PER_FLUSH) + n;
-        savepc(base);  /* in case of allocation errors */
+        savepc(L);  /* in case of allocation errors */
         if (last > h->sizearray)  /* needs more space? */
           luaH_resizearray(L, h, last);  /* preallocate it at once */
         for (; n > 0; n--) {
@@ -1506,15 +1506,14 @@ void luaV_execute (lua_State *L) {
           last--;
           luaC_barrierback(L, h, val);
         }
-        /* correct top (in case of previous open call) */
-        L->top = functop(base - 1);
+        L->top = ci->top;  /* correct top (in case of previous open call) */
         vmbreak;
       }
       vmcase(OP_CLOSURE) {
         Proto *p = cl->p->p[GETARG_Bx(i)];
         LClosure *ncl = getcached(p, cl->upvals, base);  /* cached closure */
         if (ncl == NULL) {  /* no match? */
-          savepc(base);  /* in case of allocation errors */
+          savepc(L);  /* in case of allocation errors */
           pushclosure(L, p, cl->upvals, base, ra);  /* create a new one */
         }
         else