浏览代码

yielding across lua_call (first version)

Roberto Ierusalimschy 16 年之前
父节点
当前提交
ba484b9eb1
共有 13 个文件被更改,包括 169 次插入110 次删除
  1. 13 9
      lapi.c
  2. 5 1
      lapi.h
  3. 8 3
      lbaselib.c
  4. 2 2
      ldebug.c
  5. 41 62
      ldo.c
  6. 3 2
      ldo.h
  7. 2 2
      lgc.c
  8. 2 2
      lstate.c
  9. 5 2
      lstate.h
  10. 19 11
      ltablib.c
  11. 6 2
      lua.h
  12. 61 11
      lvm.c
  13. 2 1
      lvm.h

+ 13 - 9
lapi.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lapi.c,v 2.69 2009/02/18 17:20:56 roberto Exp roberto $
+** $Id: lapi.c,v 2.70 2009/02/19 17:15:13 roberto Exp roberto $
 ** Lua API
 ** See Copyright Notice in lua.h
 */
@@ -757,21 +757,25 @@ LUA_API int lua_setfenv (lua_State *L, int idx) {
 */
 
 
-#define adjustresults(L,nres) \
-    { if (nres == LUA_MULTRET && L->top >= L->ci->top) L->ci->top = L->top; }
-
-
 #define checkresults(L,na,nr) \
      api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)))
 
 
-LUA_API void lua_call (lua_State *L, int nargs, int nresults) {
+LUA_API void lua_callcont (lua_State *L, int nargs, int nresults,
+                           lua_CFunction cont) {
   StkId func;
   lua_lock(L);
+  /* cannot use continuations inside hooks */
+  api_check(L, cont == NULL || !isLua(L->ci));
   api_checknelems(L, nargs+1);
   checkresults(L, nargs, nresults);
   func = L->top - (nargs+1);
-  luaD_call(L, func, nresults);
+  if (cont) {
+    L->ci->u.c.cont = cont;
+    luaD_call(L, func, nresults, 1);
+  }
+  else
+    luaD_call(L, func, nresults, 0);
   adjustresults(L, nresults);
   lua_unlock(L);
 }
@@ -789,7 +793,7 @@ struct CallS {  /* data to `f_call' */
 
 static void f_call (lua_State *L, void *ud) {
   struct CallS *c = cast(struct CallS *, ud);
-  luaD_call(L, c->func, c->nresults);
+  luaD_call(L, c->func, c->nresults, 0);
 }
 
 
@@ -835,7 +839,7 @@ static void f_Ccall (lua_State *L, void *ud) {
   api_incr_top(L);
   setpvalue(L->top, c->ud);  /* push only argument */
   api_incr_top(L);
-  luaD_call(L, L->top - 2, 0);
+  luaD_call(L, L->top - 2, 0, 0);
 }
 
 

+ 5 - 1
lapi.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lapi.h,v 2.2 2005/04/25 19:24:10 roberto Exp roberto $
+** $Id: lapi.h,v 2.3 2006/07/11 15:53:29 roberto Exp roberto $
 ** Auxiliary functions from Lua API
 ** See Copyright Notice in lua.h
 */
@@ -13,4 +13,8 @@
 
 #define api_incr_top(L)   {L->top++; api_check(L, L->top <= L->ci->top);}
 
+#define adjustresults(L,nres) \
+    { if ((nres) == LUA_MULTRET && L->top >= L->ci->top) L->ci->top = L->top; }
+
+
 #endif

+ 8 - 3
lbaselib.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lbaselib.c,v 1.209 2009/02/06 18:38:47 roberto Exp roberto $
+** $Id: lbaselib.c,v 1.210 2009/02/07 12:23:15 roberto Exp roberto $
 ** Basic library
 ** See Copyright Notice in lua.h
 */
@@ -323,12 +323,17 @@ static int luaB_load (lua_State *L) {
 }
 
 
+static int dofilecont (lua_State *L) {
+  return lua_gettop(L) - 1;
+}
+
+
 static int luaB_dofile (lua_State *L) {
   const char *fname = luaL_optstring(L, 1, NULL);
   lua_settop(L, 1);
   if (luaL_loadfile(L, fname) != LUA_OK) lua_error(L);
-  lua_call(L, 0, LUA_MULTRET);
-  return lua_gettop(L) - 1;
+  lua_callcont(L, 0, LUA_MULTRET, dofilecont);
+  return dofilecont(L);
 }
 
 

+ 2 - 2
ldebug.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ldebug.c,v 2.42 2008/10/30 15:39:30 roberto Exp roberto $
+** $Id: ldebug.c,v 2.43 2009/03/04 13:32:29 roberto Exp roberto $
 ** Debug Interface
 ** See Copyright Notice in lua.h
 */
@@ -628,7 +628,7 @@ void luaG_errormsg (lua_State *L) {
     setobjs2s(L, L->top, L->top - 1);  /* move argument */
     setobjs2s(L, L->top - 1, errfunc);  /* push function */
     incr_top(L);
-    luaD_call(L, L->top - 2, 1);  /* call it */
+    luaD_call(L, L->top - 2, 1, 0);  /* call it */
   }
   luaD_throw(L, LUA_ERRRUN);
 }

+ 41 - 62
ldo.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ldo.c,v 2.53 2009/03/03 18:51:24 roberto Exp roberto $
+** $Id: ldo.c,v 2.54 2009/03/04 13:32:29 roberto Exp roberto $
 ** Stack and Call structure of Lua
 ** See Copyright Notice in lua.h
 */
@@ -14,6 +14,7 @@
 
 #include "lua.h"
 
+#include "lapi.h"
 #include "ldebug.h"
 #include "ldo.h"
 #include "lfunc.h"
@@ -365,7 +366,7 @@ int luaD_poscall (lua_State *L, StkId firstResult) {
 ** When returns, all the results are on the stack, starting at the original
 ** function position.
 */
-void luaD_call (lua_State *L, StkId func, int nResults) {
+void luaD_call (lua_State *L, StkId func, int nResults, int allowyield) {
   global_State *g = G(L);
   if (++g->nCcalls >= LUAI_MAXCCALLS) {
     if (g->nCcalls == LUAI_MAXCCALLS)
@@ -373,64 +374,41 @@ void luaD_call (lua_State *L, StkId func, int nResults) {
     else if (g->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3)))
       luaD_throw(L, LUA_ERRERR);  /* error while handing stack error */
   }
+  if (!allowyield) L->nny++;
   if (!luaD_precall(L, func, nResults))  /* is a Lua function? */
     luaV_execute(L);  /* call it */
+  if (!allowyield) L->nny--;
   g->nCcalls--;
   luaC_checkGC(L);
 }
 
 
+static void finishCcall (lua_State *L) {
+  int n;
+  lua_assert(L->ci->u.c.cont != NULL);  /* must have a continuation */
+  lua_assert(L->nny == 0);
+  /* finish 'luaD_call' */
+  G(L)->nCcalls--;
+  /* finish 'lua_callcont' */
+  adjustresults(L, (L->ci + 1)->nresults);
+  /* call continuation function */
+  lua_unlock(L);
+  n = (*L->ci->u.c.cont)(L);
+  lua_lock(L);
+  /* finish 'luaD_precall' */
+  luaD_poscall(L, L->top - n);
+}
+
+
 static void unroll (lua_State *L) {
   for (;;) {
-    Instruction inst;
-    luaV_execute(L);  /* execute down to higher C 'boundary' */
-    if (L->ci == L->base_ci) {  /* stack is empty? */
-      lua_assert(L->baseCcalls == G(L)->nCcalls);
+    if (L->ci == L->base_ci)  /* stack is empty? */
       return;  /* coroutine finished normally */
-    }
-    L->baseCcalls--;  /* undo increment that allows yields */
-    inst = *(L->savedpc - 1);  /* interrupted instruction */
-    switch (GET_OPCODE(inst)) {  /* finish its execution */
-      case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV:
-      case OP_MOD: case OP_POW: case OP_UNM: case OP_LEN:
-      case OP_GETGLOBAL: case OP_GETTABLE: case OP_SELF: {
-        setobjs2s(L, L->base + GETARG_A(inst), --L->top);
-        break;
-      }
-      case OP_LE: case OP_LT: case OP_EQ: {
-        int res = !l_isfalse(L->top - 1);
-        L->top--;
-        /* metamethod should not be called when operand is K */
-        lua_assert(!ISK(GETARG_B(inst)));
-        if (GET_OPCODE(inst) == OP_LE &&  /* "<=" using "<" instead? */
-            ttisnil(luaT_gettmbyobj(L, L->base + GETARG_B(inst), TM_LE)))
-          res = !res;  /* invert result */
-        lua_assert(GET_OPCODE(*L->savedpc) == OP_JMP);
-        if (res != GETARG_A(inst))  /* condition failed? */
-          L->savedpc++;  /* skip jump instruction */
-        break;
-      }
-      case OP_CONCAT: {
-        StkId top = L->top - 1;  /* top when __concat was called */
-        int last = cast_int(top - L->base) - 2;  /* last element and ... */
-        int b = GETARG_B(inst);      /* ... first element to concatenate */
-        int total = last - b + 1;  /* number of elements to concatenate */
-        setobj2s(L, top - 2, top);  /* put TM result in proper position */
-        L->top = L->ci->top;  /* correct top */
-        if (total > 1)  /* are there elements to concat? */
-          luaV_concat(L, total, last);  /* concat them (may yield again) */
-        /* move final result to final position */
-        setobj2s(L, L->base + GETARG_A(inst), L->base + b);
-        continue;
-      }
-      case OP_TFORCALL: {
-        lua_assert(GET_OPCODE(*L->savedpc) == OP_TFORLOOP);
-        L->top = L->ci->top;  /* correct top */
-        break;
-      }
-      case OP_SETGLOBAL: case OP_SETTABLE:
-        break;  /* nothing to be done */
-      default: lua_assert(0);
+    if (!isLua(L->ci))  /* C function? */
+      finishCcall(L);
+    else {  /* Lua function */
+      luaV_finishOp(L);  /* finish interrupted instruction */
+      luaV_execute(L);  /* execute down to higher C 'boundary' */
     }
   }
 }
@@ -441,23 +419,22 @@ static void resume (lua_State *L, void *ud) {
   CallInfo *ci = L->ci;
   if (L->status == LUA_OK) {  /* start coroutine? */
     lua_assert(ci == L->base_ci && firstArg > L->base);
-    if (luaD_precall(L, firstArg - 1, LUA_MULTRET))  /* C function? */
-      return;  /* done */
+    if (!luaD_precall(L, firstArg - 1, LUA_MULTRET))  /* Lua function? */
+      luaV_execute(L);  /* call it */
   }
   else {  /* resuming from previous yield */
     lua_assert(L->status == LUA_YIELD);
     L->status = LUA_OK;
-    if (isLua(ci))  /* yielded inside a hook? */
+    if (isLua(ci)) {  /* yielded inside a hook? */
       L->base = L->ci->base;  /* just continue its execution */
+      luaV_execute(L);
+    }
     else {  /* 'common' yield */
-      /* finish interrupted execution of `OP_CALL' */
-      lua_assert(GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_CALL ||
-                 GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_TAILCALL);
-      if (luaD_poscall(L, firstArg))  /* complete it... */
-        L->top = L->ci->top;  /* and correct top if not multiple results */
+      G(L)->nCcalls--;  /* finish 'luaD_call' */
+      luaD_poscall(L, firstArg);  /* finish 'luaD_precall' */
     }
+    unroll(L);
   }
-  unroll(L);
 }
 
 
@@ -484,7 +461,7 @@ LUA_API int lua_resume (lua_State *L, int nargs) {
   if (G(L)->nCcalls >= LUAI_MAXCCALLS)
       return resume_error(L, "C stack overflow");
   ++G(L)->nCcalls;  /* count resume */
-  L->baseCcalls += G(L)->nCcalls;
+  L->nny = 0;  /* allow yields */
   status = luaD_rawrunprotected(L, resume, L->top - nargs);
   if (status != LUA_OK && status != LUA_YIELD) {  /* error? */
     L->status = cast_byte(status);  /* mark thread as `dead' */
@@ -494,7 +471,7 @@ LUA_API int lua_resume (lua_State *L, int nargs) {
   else {
     lua_assert(status == L->status);
   }
-  L->baseCcalls -= G(L)->nCcalls;
+  L->nny = 1;  /* do not allow yields */
   --G(L)->nCcalls;
   lua_unlock(L);
   return status;
@@ -504,7 +481,7 @@ LUA_API int lua_resume (lua_State *L, int nargs) {
 LUA_API int lua_yield (lua_State *L, int nresults) {
   luai_userstateyield(L, nresults);
   lua_lock(L);
-  if (G(L)->nCcalls > L->baseCcalls)
+  if (L->nny > 0)
     luaG_runerror(L, "attempt to yield across metamethod/C-call boundary");
   L->base = L->top - nresults;  /* protect stack slots below */
   L->status = LUA_YIELD;
@@ -521,6 +498,7 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u,
   int status;
   ptrdiff_t old_ci = saveci(L, L->ci);
   lu_byte old_allowhooks = L->allowhook;
+  unsigned short old_nny = L->nny;
   ptrdiff_t old_errfunc = L->errfunc;
   L->errfunc = ef;
   status = luaD_rawrunprotected(L, func, u);
@@ -532,6 +510,7 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u,
     L->base = L->ci->base;
     L->savedpc = L->ci->savedpc;
     L->allowhook = old_allowhooks;
+    L->nny = old_nny;
     restore_stack_limit(L);
   }
   L->errfunc = old_errfunc;

+ 3 - 2
ldo.h

@@ -1,5 +1,5 @@
 /*
-** $Id: ldo.h,v 2.9 2008/07/03 14:24:36 roberto Exp roberto $
+** $Id: ldo.h,v 2.10 2008/08/13 17:02:42 roberto Exp roberto $
 ** Stack and Call structure of Lua
 ** See Copyright Notice in lua.h
 */
@@ -34,7 +34,8 @@ typedef void (*Pfunc) (lua_State *L, void *ud);
 LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name);
 LUAI_FUNC void luaD_callhook (lua_State *L, int event, int line);
 LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults);
-LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults);
+LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults,
+                                        int allowyield);
 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);

+ 2 - 2
lgc.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lgc.c,v 2.47 2008/06/26 19:42:45 roberto Exp roberto $
+** $Id: lgc.c,v 2.48 2009/02/17 19:47:58 roberto Exp roberto $
 ** Garbage Collector
 ** See Copyright Notice in lua.h
 */
@@ -601,7 +601,7 @@ static Udata *udata2finalize (global_State *g) {
 
 static void dothecall (lua_State *L, void *ud) {
   UNUSED(ud);
-  luaD_call(L, L->top - 2, 0);
+  luaD_call(L, L->top - 2, 0, 0);
 }
 
 

+ 2 - 2
lstate.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lstate.c,v 2.48 2009/02/17 19:47:58 roberto Exp roberto $
+** $Id: lstate.c,v 2.49 2009/02/18 17:20:56 roberto Exp roberto $
 ** Global State
 ** See Copyright Notice in lua.h
 */
@@ -95,7 +95,7 @@ static void preinit_state (lua_State *L, global_State *g) {
   resethookcount(L);
   L->openupval = NULL;
   L->size_ci = 0;
-  L->baseCcalls = 0;
+  L->nny = 1;
   L->status = LUA_OK;
   L->base_ci = L->ci = NULL;
   L->savedpc = NULL;

+ 5 - 2
lstate.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lstate.h,v 2.37 2009/02/18 17:20:56 roberto Exp roberto $
+** $Id: lstate.h,v 2.38 2009/03/04 13:32:29 roberto Exp roberto $
 ** Global State
 ** See Copyright Notice in lua.h
 */
@@ -87,6 +87,9 @@ typedef struct CallInfo {
     struct {  /* only for Lua functions */
       int tailcalls;  /* number of tail calls lost under this entry */
     } l;
+    struct {  /* only for C functions */
+      lua_CFunction cont;  /* continuation in case of yields */
+    } c;
   } u;
 } CallInfo;
 
@@ -160,7 +163,7 @@ struct lua_State {
   CallInfo *base_ci;  /* array of CallInfo's */
   int stacksize;
   int size_ci;  /* size of array `base_ci' */
-  unsigned short baseCcalls;  /* number of nested C calls when resuming */
+  unsigned short nny;  /* number of non-yieldable calls in stack */
   lu_byte hookmask;
   lu_byte allowhook;
   int basehookcount;

+ 19 - 11
ltablib.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ltablib.c,v 1.43 2008/02/14 16:03:27 roberto Exp roberto $
+** $Id: ltablib.c,v 1.44 2008/04/07 18:43:00 roberto Exp roberto $
 ** Library for Table Manipulation
 ** See Copyright Notice in lua.h
 */
@@ -36,20 +36,28 @@ static int foreachi (lua_State *L) {
 }
 
 
-static int foreach (lua_State *L) {
-  luaL_checktype(L, 1, LUA_TTABLE);
-  luaL_checktype(L, 2, LUA_TFUNCTION);
-  lua_pushnil(L);  /* first key */
-  while (lua_next(L, 1)) {
-    lua_pushvalue(L, 2);  /* function */
-    lua_pushvalue(L, -3);  /* key */
-    lua_pushvalue(L, -3);  /* value */
-    lua_call(L, 2, 1);
+static int foreachcont (lua_State *L) {
+  for (;;) {
     if (!lua_isnil(L, -1))
       return 1;
     lua_pop(L, 2);  /* remove value and result */
+    if (lua_next(L, 1) == 0)  /* no more elements? */
+      return 0;
+    lua_pushvalue(L, 2);  /* function */
+    lua_pushvalue(L, -3);  /* key */
+    lua_pushvalue(L, -3);  /* value */
+    lua_callcont(L, 2, 1, &foreachcont);
   }
-  return 0;
+}
+
+
+static int foreach (lua_State *L) {
+  luaL_checktype(L, 1, LUA_TTABLE);
+  luaL_checktype(L, 2, LUA_TFUNCTION);
+  lua_pushnil(L);  /* first key */
+  lua_pushnil(L);  /* first value */
+  lua_pushnil(L);  /* first "return" */
+  return foreachcont(L);
 }
 
 

+ 6 - 2
lua.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lua.h,v 1.231 2008/08/13 14:08:49 roberto Exp roberto $
+** $Id: lua.h,v 1.232 2009/02/18 17:20:56 roberto Exp roberto $
 ** Lua - An Extensible Extension Language
 ** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
 ** See Copyright Notice at the end of this file
@@ -203,7 +203,9 @@ LUA_API int   (lua_setfenv) (lua_State *L, int idx);
 /*
 ** 'load' and 'call' functions (load and run Lua code)
 */
-LUA_API void  (lua_call) (lua_State *L, int nargs, int nresults);
+LUA_API void  (lua_callcont) (lua_State *L, int nargs, int nresults,
+                              lua_CFunction cont);
+
 LUA_API int   (lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc);
 LUA_API int   (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud);
 LUA_API int   (lua_load) (lua_State *L, lua_Reader reader, void *dt,
@@ -281,6 +283,8 @@ LUA_API void      (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);
 
 #define lua_tostring(L,i)	lua_tolstring(L, (i), NULL)
 
+#define lua_call(L,n,r)		lua_callcont(L, (n), (r), NULL);
+
 
 
 /*

+ 61 - 11
lvm.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lvm.c,v 2.82 2009/03/02 16:34:23 roberto Exp roberto $
+** $Id: lvm.c,v 2.83 2009/03/04 13:32:29 roberto Exp roberto $
 ** Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -79,17 +79,14 @@ static void traceexec (lua_State *L) {
 static void callTM (lua_State *L, const TValue *f, const TValue *p1,
                     const TValue *p2, TValue *p3, int hasres) {
   ptrdiff_t result = savestack(L, p3);
-  int oldbase = L->baseCcalls;
   setobj2s(L, L->top++, f);  /* push function */
   setobj2s(L, L->top++, p1);  /* 1st argument */
   setobj2s(L, L->top++, p2);  /* 2nd argument */
   if (!hasres)  /* no result? 'p3' is third argument */
     setobj2s(L, L->top++, p3);  /* 3th argument */
   luaD_checkstack(L, 0);
-  if (isLua(L->ci))  /* metamethod invoked from a Lua function? */
-    L->baseCcalls++;  /* allow it to yield */
-  luaD_call(L, L->top - (4 - hasres), hasres);
-  L->baseCcalls = oldbase;
+  /* metamethod may yield only when called from Lua code */
+  luaD_call(L, L->top - (4 - hasres), hasres, isLua(L->ci));
   if (hasres) {  /* if has result, move it to its place */
     p3 = restorestack(L, result);
     setobjs2s(L, p3, --L->top);
@@ -356,6 +353,61 @@ static void Arith (lua_State *L, StkId ra, const TValue *rb,
 }
 
 
+/*
+** finish execution of an opcode interrupted by an yield
+*/
+void luaV_finishOp (lua_State *L) {
+  Instruction inst = *(L->savedpc - 1);  /* interrupted instruction */
+  switch (GET_OPCODE(inst)) {  /* finish its execution */
+    case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV:
+    case OP_MOD: case OP_POW: case OP_UNM: case OP_LEN:
+    case OP_GETGLOBAL: case OP_GETTABLE: case OP_SELF: {
+      setobjs2s(L, L->base + GETARG_A(inst), --L->top);
+      break;
+    }
+    case OP_LE: case OP_LT: case OP_EQ: {
+      int res = !l_isfalse(L->top - 1);
+      L->top--;
+      /* metamethod should not be called when operand is K */
+      lua_assert(!ISK(GETARG_B(inst)));
+      if (GET_OPCODE(inst) == OP_LE &&  /* "<=" using "<" instead? */
+          ttisnil(luaT_gettmbyobj(L, L->base + GETARG_B(inst), TM_LE)))
+        res = !res;  /* invert result */
+      lua_assert(GET_OPCODE(*L->savedpc) == OP_JMP);
+      if (res != GETARG_A(inst))  /* condition failed? */
+        L->savedpc++;  /* skip jump instruction */
+      break;
+    }
+    case OP_CONCAT: {
+      StkId top = L->top - 1;  /* top when __concat was called */
+      int last = cast_int(top - L->base) - 2;  /* last element and ... */
+      int b = GETARG_B(inst);      /* ... first element to concatenate */
+      int total = last - b + 1;  /* number of elements to concatenate */
+      setobj2s(L, top - 2, top);  /* put TM result in proper position */
+      L->top = L->ci->top;  /* correct top */
+      if (total > 1)  /* are there elements to concat? */
+        luaV_concat(L, total, last);  /* concat them (may yield again) */
+      /* move final result to final position */
+      setobj2s(L, L->base + GETARG_A(inst), L->base + b);
+      break;
+    }
+    case OP_TFORCALL: {
+      lua_assert(GET_OPCODE(*L->savedpc) == OP_TFORLOOP);
+      L->top = L->ci->top;  /* correct top */
+      break;
+    }
+    case OP_CALL: {
+      if (GETARG_C(inst) - 1 >= 0)  /* nresults >= 0? */
+        L->top = L->ci->top;  /* adjust results */
+      break;
+    }
+    case OP_TAILCALL: case OP_SETGLOBAL: case OP_SETTABLE:
+      break;
+    default: lua_assert(0);
+  }
+}
+
+
 
 /*
 ** some macros for common tasks in `luaV_execute'
@@ -672,11 +724,9 @@ void luaV_execute (lua_State *L) {
         setobjs2s(L, cb+2, ra+2);
         setobjs2s(L, cb+1, ra+1);
         setobjs2s(L, cb, ra);
-        L->baseCcalls++;  /* allow yields */
         L->top = cb + 3;  /* func. + 2 args (state and index) */
-        Protect(luaD_call(L, cb, GETARG_C(i)));
+        Protect(luaD_call(L, cb, GETARG_C(i), 1));
         L->top = L->ci->top;
-        L->baseCcalls--;
         i = *(L->savedpc++);  /* go to next instruction */
         ra = RA(i);
         lua_assert(GET_OPCODE(i) == OP_TFORLOOP);
@@ -725,8 +775,8 @@ void luaV_execute (lua_State *L) {
         ncl = luaF_newLclosure(L, nup, cl->env);
         ncl->l.p = p;
         setclvalue(L, ra, ncl);
-        for (j=0; j<nup; j++, L->savedpc++) {
-          Instruction u = *L->savedpc;
+        for (j=0; j<nup; j++) {
+          Instruction u = *L->savedpc++;
           if (GET_OPCODE(u) == OP_GETUPVAL)
             ncl->l.upvals[j] = cl->upvals[GETARG_B(u)];
           else {

+ 2 - 1
lvm.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lvm.h,v 2.6 2007/02/09 13:04:52 roberto Exp roberto $
+** $Id: lvm.h,v 2.7 2008/08/26 13:27:42 roberto Exp roberto $
 ** Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -32,6 +32,7 @@ LUAI_FUNC void luaV_gettable (lua_State *L, const TValue *t, TValue *key,
                                             StkId val);
 LUAI_FUNC void luaV_settable (lua_State *L, const TValue *t, TValue *key,
                                             StkId val);
+LUAI_FUNC void luaV_finishOp (lua_State *L);
 LUAI_FUNC void luaV_execute (lua_State *L);
 LUAI_FUNC void luaV_concat (lua_State *L, int total, int last);