Explorar el Código

first implementation of coroutines

Roberto Ierusalimschy hace 23 años
padre
commit
f083812c02
Se han modificado 11 ficheros con 229 adiciones y 137 borrados
  1. 46 35
      lbaselib.c
  2. 1 2
      lcode.c
  3. 8 7
      ldebug.c
  4. 110 16
      ldo.c
  5. 14 5
      lopcodes.h
  6. 5 5
      lparser.c
  7. 1 0
      lstate.c
  8. 5 1
      lstate.h
  9. 9 8
      lua.h
  10. 29 57
      lvm.c
  11. 1 1
      lvm.h

+ 46 - 35
lbaselib.c

@@ -148,30 +148,6 @@ static int luaB_eventtable (lua_State *L) {
 }
 
 
-static int luaB_weakmode (lua_State *L) {
-  const char *mode = luaL_check_string(L, 2);
-  luaL_check_type(L, 1, LUA_TTABLE);
-  if (*mode == '?') {
-    char buff[3];
-    char *s = buff;
-    int imode = lua_getweakmode(L, 1);
-    if (imode & LUA_WEAK_KEY) *s++ = 'k';
-    if (imode & LUA_WEAK_VALUE) *s++ = 'v';
-    *s = '\0';
-    lua_pushstring(L, buff);
-    return 1;
-  }
-  else {
-    int imode = 0;
-    if (strchr(mode, 'k')) imode |= LUA_WEAK_KEY;
-    if (strchr(mode, 'v')) imode |= LUA_WEAK_VALUE;
-    lua_pushvalue(L, 1);  /* push table */
-    lua_setweakmode(L, imode);
-    return 1;  /* return the table */
-  }
-}
-
-
 static int luaB_globals (lua_State *L) {
   lua_getglobals(L);  /* value to be returned */
   if (!lua_isnone(L, 1)) {
@@ -287,6 +263,14 @@ static int luaB_loadfile (lua_State *L) {
 }
 
 
+static int luaB_assert (lua_State *L) {
+  luaL_check_any(L, 1);
+  if (!lua_istrue(L, 1))
+    luaL_verror(L, "assertion failed!  %.90s", luaL_opt_string(L, 2, ""));
+  lua_settop(L, 1);
+  return 1;
+}
+
 
 #define LUA_PATH	"LUA_PATH"
 
@@ -428,6 +412,40 @@ static int luaB_tostring (lua_State *L) {
 }
 
 
+static int luaB_resume (lua_State *L) {
+  lua_State *co = (lua_State *)lua_touserdata(L, lua_upvalueindex(1));
+  lua_resume(L, co);
+  return 0;
+}
+
+
+static int luaB_coroutine (lua_State *L) {
+  lua_State *NL;
+  int ref;
+  luaL_check_type(L, 1, LUA_TFUNCTION);
+  NL = lua_newthread(L, 0);
+  if (NL == NULL) lua_error(L, "unable to create new thread");
+  /* move function from L to NL */
+  ref = lua_ref(L, 1);
+  lua_getref(NL, ref);
+  lua_unref(L, ref);
+  lua_cobegin(NL, 0);
+  lua_newuserdatabox(L, NL);
+  lua_pushcclosure(L, luaB_resume, 1);
+  return 1;
+}
+
+
+static int luaB_yield (lua_State *L) {
+  return lua_yield(L, 0);
+}
+
+
+/*
+** {======================================================
+** Auxiliar table-related functions
+*/
+
 static int luaB_foreachi (lua_State *L) {
   int n, i;
   luaL_check_type(L, 1, LUA_TTABLE);
@@ -464,15 +482,6 @@ static int luaB_foreach (lua_State *L) {
 }
 
 
-static int luaB_assert (lua_State *L) {
-  luaL_check_any(L, 1);
-  if (!lua_istrue(L, 1))
-    luaL_verror(L, "assertion failed!  %.90s", luaL_opt_string(L, 2, ""));
-  lua_settop(L, 1);
-  return 1;
-}
-
-
 static int luaB_getn (lua_State *L) {
   luaL_check_type(L, 1, LUA_TTABLE);
   lua_pushnumber(L, lua_getn(L, 1));
@@ -521,7 +530,6 @@ static int luaB_tremove (lua_State *L) {
 
 
 
-
 /*
 ** {======================================================
 ** Quicksort
@@ -627,6 +635,8 @@ static int luaB_sort (lua_State *L) {
 
 /* }====================================================== */
 
+/* }====================================================== */
+
 
 
 static const luaL_reg base_funcs[] = {
@@ -634,6 +644,7 @@ static const luaL_reg base_funcs[] = {
   {LUA_ERRORMESSAGE, luaB__ERRORMESSAGE},
   {"call", luaB_call},
   {"collectgarbage", luaB_collectgarbage},
+  {"coroutine", luaB_coroutine},
   {"dofile", luaB_dofile},
   {"dostring", luaB_dostring},
   {"error", luaB_error},
@@ -659,7 +670,7 @@ static const luaL_reg base_funcs[] = {
   {"tinsert", luaB_tinsert},
   {"tremove", luaB_tremove},
   {"unpack", luaB_unpack},
-  {"weakmode", luaB_weakmode}
+  {"yield", luaB_yield}
 };
 
 

+ 1 - 2
lcode.c

@@ -264,8 +264,7 @@ static int nil_constant (FuncState *fs) {
 
 void luaK_setcallreturns (FuncState *fs, expdesc *e, int nresults) {
   if (e->k == VCALL) {  /* expression is an open function call? */
-    if (nresults == LUA_MULTRET) nresults = NO_REG;
-    SETARG_C(getcode(fs, e), nresults);
+    SETARG_C(getcode(fs, e), nresults+1);
     if (nresults == 1) {  /* `regular' expression? */
       e->k = VNONRELOC;
       e->u.i.info = GETARG_A(getcode(fs, e));

+ 8 - 7
ldebug.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ldebug.c,v 1.1 2001/11/29 22:14:34 rieru Exp rieru $
+** $Id: ldebug.c,v 1.96 2001/12/18 20:52:30 roberto Exp $
 ** Debug Interface
 ** See Copyright Notice in lua.h
 */
@@ -303,7 +303,7 @@ static int checkopenop (const Proto *pt, int pc) {
   switch (GET_OPCODE(i)) {
     case OP_CALL:
     case OP_RETURN: {
-      check(GETARG_B(i) == NO_REG);
+      check(GETARG_B(i) == 0);
       return 1;
     }
     case OP_SETLISTO: return 1;
@@ -391,10 +391,11 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) {
         break;
       }
       case OP_CALL: {
-        if (b != NO_REG) {
-          checkreg(pt, a+b);
+        if (b != 0) {
+          checkreg(pt, a+b-1);
         }
-        if (c == NO_REG) {
+        c--;  /* c = num. returns */
+        if (c == LUA_MULTRET) {
           check(checkopenop(pt, pc));
         }
         else if (c != 0)
@@ -403,8 +404,8 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) {
         break;
       }
       case OP_RETURN: {
-        if (b != NO_REG && b != 0)
-          checkreg(pt, a+b-1);
+        b--;  /* b = num. returns */
+        if (b > 0) checkreg(pt, a+b-1);
         break;
       }
       case OP_FORPREP:

+ 110 - 16
ldo.c

@@ -18,6 +18,7 @@
 #include "lgc.h"
 #include "lmem.h"
 #include "lobject.h"
+#include "lopcodes.h"
 #include "lparser.h"
 #include "lstate.h"
 #include "lstring.h"
@@ -112,8 +113,6 @@ void luaD_callHook (lua_State *L, lua_Hook callhook, const char *event) {
 }
 
 
-#define newci(L)	((++L->ci == L->end_ci) ? growci(L) : L->ci)
-
 static CallInfo *growci (lua_State *L) {
   lua_assert(L->ci == L->end_ci);
   luaM_reallocvector(L, L->base_ci, L->size_ci, 2*L->size_ci, CallInfo);
@@ -124,9 +123,32 @@ static CallInfo *growci (lua_State *L) {
 }
 
 
+static void adjust_varargs (lua_State *L, StkId base, int nfixargs) {
+  int i;
+  Table *htab;
+  TObject n, nname;
+  StkId firstvar = base + nfixargs;  /* position of first vararg */
+  if (L->top < firstvar) {
+    luaD_checkstack(L, firstvar - L->top);
+    while (L->top < firstvar)
+      setnilvalue(L->top++);
+  }
+  htab = luaH_new(L, 0, 0);
+  for (i=0; firstvar+i<L->top; i++)
+    luaH_setnum(L, htab, i+1, firstvar+i);
+  /* store counter in field `n' */
+  setnvalue(&n, i);
+  setsvalue(&nname, luaS_newliteral(L, "n"));
+  luaH_set(L, htab, &nname, &n);
+  L->top = firstvar;  /* remove elements from the stack */
+  sethvalue(L->top, htab);
+  incr_top;
+}
+
+
 StkId luaD_precall (lua_State *L, StkId func) {
   CallInfo *ci;
-  int n;
+  LClosure *cl;
   if (ttype(func) != LUA_TFUNCTION) {
     /* `func' is not a function; check the `function' tag method */
     const TObject *tm = luaT_gettmbyobj(L, func, TM_CALL);
@@ -135,21 +157,39 @@ StkId luaD_precall (lua_State *L, StkId func) {
     luaD_openstack(L, func);
     setobj(func, tm);  /* tag method is the new function to be called */
   }
-  ci = newci(L);
+  ci = ++L->ci;
+  if (L->ci == L->end_ci) ci = growci(L);
   ci->base = func+1;
-  ci->savedpc = NULL;
   if (L->callhook)
     luaD_callHook(L, L->callhook, "call");
-  if (!clvalue(func)->c.isC) return NULL;
-  /* if is a C function, call it */
-  luaD_checkstack(L, LUA_MINSTACK);  /* ensure minimum stack size */
-  lua_unlock(L);
+  cl = &clvalue(func)->l;
+  if (!cl->isC) {  /* Lua function? prepare its call */
+    StkId base = func+1;
+    Proto *p = cl->p;
+    ci->linehook = L->linehook;
+    ci->savedpc = p->code;  /* starting point */
+    if (p->is_vararg)  /* varargs? */
+      adjust_varargs(L, base, p->numparams);
+    if (base > L->stack_last - p->maxstacksize)
+      luaD_stackerror(L);
+    ci->top = base + p->maxstacksize;
+    while (L->top < ci->top)
+      setnilvalue(L->top++);
+    L->top = ci->top;
+    return NULL;
+  }
+  else {  /* if is a C function, call it */
+    int n;
+    ci->savedpc = NULL;
+    luaD_checkstack(L, LUA_MINSTACK);  /* ensure minimum stack size */
+    lua_unlock(L);
 #if LUA_COMPATUPVALUES
-  lua_pushupvalues(L);
+    lua_pushupvalues(L);
 #endif
-  n = (*clvalue(func)->c.f)(L);  /* do the actual call */
-  lua_lock(L);
-  return L->top - n;
+    n = (*clvalue(func)->c.f)(L);  /* do the actual call */
+    lua_lock(L);
+    return L->top - n;
+  }
 }
 
 
@@ -179,12 +219,60 @@ void luaD_poscall (lua_State *L, int wanted, StkId firstResult) {
 */ 
 void luaD_call (lua_State *L, StkId func, int nResults) {
   StkId firstResult = luaD_precall(L, func);
-  if (firstResult == NULL)  /* is a Lua function? */
-    firstResult = luaV_execute(L, &clvalue(func)->l, func+1);  /* call it */
+  if (firstResult == NULL) {  /* is a Lua function? */
+    firstResult = luaV_execute(L);  /* call it */
+    if (firstResult == NULL) {
+      luaD_poscall(L, 0, L->top);
+      luaD_error(L, "attempt to `yield' across tag-method/C-call boundary");
+    }
+  }
   luaD_poscall(L, nResults, firstResult);
 }
 
 
+LUA_API void lua_cobegin (lua_State *L, int nargs) {
+  StkId func;
+  lua_lock(L);
+  func = L->top - (nargs+1);  /* coroutine main function */
+  if (luaD_precall(L, func) != NULL)
+    luaD_error(L, "coroutine started with a C function");
+  lua_unlock(L);
+}
+
+
+LUA_API void lua_resume (lua_State *L, lua_State *co) {
+  StkId firstResult;
+  lua_lock(L);
+  if (co->ci->savedpc == NULL)  /* no activation record? */
+    luaD_error(L, "thread is dead - cannot be resumed");
+  lua_assert(co->errorJmp == NULL);
+  co->errorJmp = L->errorJmp;
+  firstResult = luaV_execute(co);
+  if (firstResult != NULL)  /* `return'? */
+    luaD_poscall(co, LUA_MULTRET, firstResult);  /* ends this coroutine */
+  else {  /* `yield' */
+    int nresults = GETARG_C(*((co->ci-1)->savedpc - 1)) - 1;
+    luaD_poscall(co, nresults, co->top);  /* complete it */
+    if (nresults >= 0) co->top = co->ci->top;
+  }
+  co->errorJmp = NULL;
+  lua_unlock(L);
+}
+
+
+LUA_API int lua_yield (lua_State *L, int nresults) {
+  CallInfo *ci;
+  int ibase;
+  lua_lock(L);
+  ci = L->ci - 1;  /* call info of calling function */
+  if (ci->pc == NULL)
+    luaD_error(L, "cannot `yield' a C function");
+  ibase = L->top - ci->base;
+  lua_unlock(L);
+  return ibase;
+}
+
+
 /*
 ** Execute a protected call.
 */
@@ -330,7 +418,13 @@ static void message (lua_State *L, const char *s) {
 ** Reports an error, and jumps up to the available recovery label
 */
 void luaD_error (lua_State *L, const char *s) {
-  if (s) message(L, s);
+  if (s) {
+    if (L->ci->savedpc) {  /* error in Lua function preamble? */
+      L->ci->savedpc = NULL;  /* pretend function was already running */
+      L->ci->pc = NULL;
+    }
+    message(L, s);
+  }
   luaD_breakrun(L, LUA_ERRRUN);
 }
 

+ 14 - 5
lopcodes.h

@@ -168,8 +168,8 @@ OP_TESTGE,/*	A C	test := (R(A) >= R/K(C))			*/
 OP_TESTT,/*	A B	test := R(B); if (test) R(A) := R(B)		*/
 OP_TESTF,/*	A B	test := not R(B); if (test) R(A) := R(B)	*/
 
-OP_CALL,/*	A B C	R(A), ... ,R(A+C-1) := R(A)(R(A+1), ... ,R(A+B))*/
-OP_RETURN,/*	A B	return R(A), ... ,R(A+B-1)	(see (3))	*/
+OP_CALL,/*	A B C	R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1))*/
+OP_RETURN,/*	A B	return R(A), ... ,R(A+B-2)	(see (3))	*/
 
 OP_FORPREP,/*	A sBc							*/
 OP_FORLOOP,/*	A sBc							*/
@@ -182,6 +182,9 @@ OP_SETLISTO,/*	A Bc							*/
 
 OP_CLOSE,/*	A 	close all variables in the stack up to (>=) R(A)*/
 OP_CLOSURE /*	A Bc	R(A) := closure(KPROTO[Bc], R(A), ... ,R(A+n))	*/
+/*----------------------------------------------------------------------
+pseudo-instructions (interruptions): cannot occur in regular code
+------------------------------------------------------------------------*/
 } OpCode;
 
 
@@ -194,11 +197,11 @@ OP_CLOSURE /*	A Bc	R(A) := closure(KPROTO[Bc], R(A), ... ,R(A+n))	*/
   (1) In the current implementation there is no `test' variable;
       instructions OP_TEST* and OP_CJMP must always occur together.
 
-  (2) In OP_CALL, if (B == NO_REG) then B = top. C is the number of returns,
-      and can be NO_REG. OP_CALL can set `top' to last_result+1, so
+  (2) In OP_CALL, if (B == 0) then B = top. C is the number of returns - 1,
+      and can be 0: OP_CALL then sets `top' to last_result+1, so
       next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use `top'.
 
-  (3) In OP_RETURN, if (B == NO_REG) then return up to `top'
+  (3) In OP_RETURN, if (B == 0) then return up to `top'
 ===========================================================================*/
 
 
@@ -220,6 +223,12 @@ extern const lu_byte luaP_opmodes[NUM_OPCODES];
 #define testOpMode(m, b)        (luaP_opmodes[m] & (1 << (b)))
 
 
+/*
+** constant instructions
+*/
+
+extern const Instruction luaP_yieldop;
+
 /*
 ** opcode names (only included when compiled with LUA_OPNAMES)
 */

+ 5 - 5
lparser.c

@@ -335,7 +335,7 @@ static void close_func (LexState *ls) {
   FuncState *fs = ls->fs;
   Proto *f = fs->f;
   removelocalvars(ls, fs->nactloc, 0);
-  luaK_codeABC(fs, OP_RETURN, 0, 0, 0);  /* final return */
+  luaK_codeABC(fs, OP_RETURN, 0, 1, 0);  /* final return */
   luaK_getlabel(fs);  /* close eventual list of pending jumps */
   lua_assert(G(L)->roottable == fs->h);
   G(L)->roottable = fs->h->next;
@@ -449,13 +449,13 @@ static void funcargs (LexState *ls, expdesc *f) {
   lua_assert(f->k == VNONRELOC);
   base = f->u.i.info;  /* base register for call */
   if (args.k == VCALL)
-    nparams = NO_REG;  /* open call */
+    nparams = LUA_MULTRET;  /* open call */
   else {
     if (args.k != VVOID)
       luaK_exp2nextreg(fs, &args);  /* close last argument */
     nparams = fs->freereg - (base+1);
   }
-  init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams, 1));
+  init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2));
   fs->freereg = base+1;  /* call remove function and arguments and leaves
                             (unless changed) one result */
 }
@@ -1136,7 +1136,7 @@ static void retstat (LexState *ls) {
     if (e.k == VCALL) {
       luaK_setcallreturns(fs, &e, LUA_MULTRET);
       first = fs->nactloc;
-      nret = NO_REG;  /* return all values */
+      nret = LUA_MULTRET;  /* return all values */
     }
     else {
       luaK_exp2nextreg(fs, &e);  /* values must go to the `stack' */
@@ -1144,7 +1144,7 @@ static void retstat (LexState *ls) {
       nret = fs->freereg - first;  /* return all `active' values */
     }
   }
-  luaK_codeABC(fs, OP_RETURN, first, nret, 0);
+  luaK_codeABC(fs, OP_RETURN, first, nret+1, 0);
   fs->freereg = fs->nactloc;  /* removes all temp values */
 }
 

+ 1 - 0
lstate.c

@@ -104,6 +104,7 @@ LUA_API lua_State *lua_newthread (lua_State *OL, int stacksize) {
     }
   }
   if (OL) lua_unlock(OL);
+  lua_userstateopen(L);
   return L;
 }
 

+ 5 - 1
lstate.h

@@ -39,6 +39,10 @@
 #define LUA_USERSTATE
 #endif
 
+#ifndef lua_userstateopen
+#define lua_userstateopen(l)
+#endif
+
 
 
 struct lua_longjmp;  /* defined in ldo.c */
@@ -77,8 +81,8 @@ typedef struct CallInfo {
   const Instruction *savedpc;
   lua_Hook linehook;
   StkId	top;  /* top for this function (when it's a Lua function) */
-  /* extra information for debugging */
   const Instruction **pc;
+  /* extra information for line tracing */
   int lastpc;  /* last pc traced */
   int line;  /* current line */
   int refi;  /* current index in `lineinfo' */

+ 9 - 8
lua.h

@@ -45,10 +45,6 @@
 #define LUA_ERRMEM	4
 #define LUA_ERRERR	5
 
-/* weak-table modes */
-#define LUA_WEAK_KEY	1
-#define LUA_WEAK_VALUE	2
-
 
 typedef struct lua_State lua_State;
 
@@ -182,6 +178,14 @@ LUA_API int   lua_loadbuffer (lua_State *L, const char *buff, size_t size,
 LUA_API int   lua_dobuffer (lua_State *L, const char *buff, size_t size,
                             const char *name);
 
+
+/*
+** coroutine functions
+*/
+LUA_API void lua_cobegin (lua_State *L, int nargs);
+LUA_API int  lua_yield (lua_State *L, int nresults);
+LUA_API void lua_resume (lua_State *L, lua_State *co);
+
 /*
 ** Garbage-collection functions
 */
@@ -203,9 +207,6 @@ LUA_API void  lua_concat (lua_State *L, int n);
 LUA_API void *lua_newuserdata (lua_State *L, size_t size);
 LUA_API void  lua_newuserdatabox (lua_State *L, void *u);
 
-LUA_API void  lua_setweakmode (lua_State *L, int mode);
-LUA_API int   lua_getweakmode (lua_State *L, int index);
-
 
 
 /* 
@@ -242,7 +243,7 @@ LUA_API int   lua_getweakmode (lua_State *L, int index);
 ** compatibility macros and functions
 */
 
-LUA_API void lua_pushupvalues (lua_State *L);
+LUA_API int lua_pushupvalues (lua_State *L);
 
 #define lua_isnull	lua_isnone
 

+ 29 - 57
lvm.c

@@ -254,29 +254,6 @@ void luaV_strconc (lua_State *L, int total, StkId top) {
 }
 
 
-static void adjust_varargs (lua_State *L, StkId base, int nfixargs) {
-  int i;
-  Table *htab;
-  TObject n, nname;
-  StkId firstvar = base + nfixargs;  /* position of first vararg */
-  if (L->top < firstvar) {
-    luaD_checkstack(L, firstvar - L->top);
-    while (L->top < firstvar)
-      setnilvalue(L->top++);
-  }
-  htab = luaH_new(L, 0, 0);
-  for (i=0; firstvar+i<L->top; i++)
-    luaH_setnum(L, htab, i+1, firstvar+i);
-  /* store counter in field `n' */
-  setnvalue(&n, i);
-  setsvalue(&nname, luaS_newliteral(L, "n"));
-  luaH_set(L, htab, &nname, &n);
-  L->top = firstvar;  /* remove elements from the stack */
-  sethvalue(L->top, htab);
-  incr_top;
-}
-
-
 static void powOp (lua_State *L, StkId ra, StkId rb, StkId rc) {
   const TObject *b = rb;
   const TObject *c = rc;
@@ -307,8 +284,8 @@ static void powOp (lua_State *L, StkId ra, StkId rb, StkId rc) {
 #define RC(i)	(base+GETARG_C(i))
 #define RKC(i)	((GETARG_C(i) < MAXSTACK) ? \
 			base+GETARG_C(i) : \
-			cl->p->k+GETARG_C(i)-MAXSTACK)
-#define KBc(i)	(cl->p->k+GETARG_Bc(i))
+			k+GETARG_C(i)-MAXSTACK)
+#define KBc(i)	(k+GETARG_Bc(i))
 
 #define Arith(op, optm)	{ \
   const TObject *b = RB(i); const TObject *c = RKC(i);		\
@@ -321,38 +298,26 @@ static void powOp (lua_State *L, StkId ra, StkId rb, StkId rc) {
 }
 
 
-#define luaV_poscall(L,c,f,ci) \
-  if (c != NO_REG) { \
-    luaD_poscall(L, c, f); \
-    L->top = ci->top; \
-  } \
-  else { \
-    luaD_poscall(L, LUA_MULTRET, f); \
-  }
-
-
 #define dojump(pc, i)	((pc) += GETARG_sBc(i))
 
 /*
-** Executes the given Lua function. Parameters are between [base,top).
+** Executes current Lua function. Parameters are between [base,top).
 ** Returns n such that the results are between [n,top).
 */
-StkId luaV_execute (lua_State *L, const LClosure *cl, StkId base) {
+StkId luaV_execute (lua_State *L) {
+  StkId base;
+  LClosure *cl;
+  TObject *k;
   const Instruction *pc;
   lua_Hook linehook;
  reinit:
-  lua_assert(L->ci->savedpc == NULL);
+  base = L->ci->base;
+  cl = &clvalue(base - 1)->l;
+  k = cl->p->k;
+  linehook = L->ci->linehook;
   L->ci->pc = &pc;
-  L->ci->top = base + cl->p->maxstacksize;
-  if (cl->p->is_vararg)  /* varargs? */
-    adjust_varargs(L, base, cl->p->numparams);
-  if (base > L->stack_last - cl->p->maxstacksize)
-    luaD_stackerror(L);
-  while (L->top < L->ci->top)
-    setnilvalue(L->top++);
-  L->top = L->ci->top;
-  linehook = L->ci->linehook = L->linehook;
-  pc = cl->p->code;
+  pc = L->ci->savedpc;
+  L->ci->savedpc = NULL;
   /* main loop of interpreter */
   for (;;) {
     const Instruction i = *pc++;
@@ -535,18 +500,21 @@ StkId luaV_execute (lua_State *L, const LClosure *cl, StkId base) {
       case OP_CALL: {
         StkId firstResult;
         int b = GETARG_B(i);
-        if (b != NO_REG) L->top = ra+b+1;
-        /* else previous instruction set top */
+        int nresults;
+        if (b != 0) L->top = ra+b;  /* else previous instruction set top */
+        nresults = GETARG_C(i) - 1;
         firstResult = luaD_precall(L, ra);
         if (firstResult) {
+          if (firstResult == base) {  /* yield?? */
+            (L->ci-1)->savedpc = pc;
+            return NULL;
+          }
           /* it was a C function (`precall' called it); adjust results */
-          luaV_poscall(L, GETARG_C(i), firstResult, L->ci);
+          luaD_poscall(L, nresults, firstResult);
+          if (nresults >= 0) L->top = L->ci->top;
         }
         else {  /* it is a Lua function: `call' it */
-          CallInfo *ci = L->ci;
-          (ci-1)->savedpc = pc;
-          base = ci->base;
-          cl = &clvalue(base - 1)->l;
+          (L->ci-1)->savedpc = pc;
           goto reinit;
         }
         break;
@@ -556,19 +524,23 @@ StkId luaV_execute (lua_State *L, const LClosure *cl, StkId base) {
         int b;
         if (L->openupval) luaF_close(L, base);
         b = GETARG_B(i);
-        if (b != NO_REG) L->top = ra+b;
+        if (b != 0) L->top = ra+b-1;
         ci = L->ci - 1;
         if (ci->savedpc == NULL)
           return ra;
         else {  /* previous function is Lua: continue its execution */
+          int nresults;
           lua_assert(ttype(ci->base-1) == LUA_TFUNCTION);
           base = ci->base;  /* restore previous values */
           linehook = ci->linehook;
           cl = &clvalue(base - 1)->l;
+          k = cl->p->k;
           pc = ci->savedpc;
           ci->savedpc = NULL;
           lua_assert(GET_OPCODE(*(pc-1)) == OP_CALL);
-          luaV_poscall(L, GETARG_C(*(pc-1)), ra, ci);
+          nresults = GETARG_C(*(pc-1)) - 1;
+          luaD_poscall(L, nresults, ra);
+          if (nresults >= 0) L->top = L->ci->top;
         }
         break;
       }

+ 1 - 1
lvm.h

@@ -20,7 +20,7 @@ const TObject *luaV_tonumber (const TObject *obj, TObject *n);
 int luaV_tostring (lua_State *L, TObject *obj);
 void luaV_gettable (lua_State *L, StkId t, TObject *key, StkId res);
 void luaV_settable (lua_State *L, StkId t, TObject *key, StkId val);
-StkId luaV_execute (lua_State *L, const LClosure *cl, StkId base);
+StkId luaV_execute (lua_State *L);
 int luaV_lessthan (lua_State *L, const TObject *l, const TObject *r);
 void luaV_strconc (lua_State *L, int total, StkId top);