瀏覽代碼

concat TM can yield

Roberto Ierusalimschy 16 年之前
父節點
當前提交
b472098493
共有 2 個文件被更改,包括 24 次插入12 次删除
  1. 21 11
      ldo.c
  2. 3 1
      lvm.c

+ 21 - 11
ldo.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ldo.c,v 2.49 2008/10/28 16:53:16 roberto Exp roberto $
+** $Id: ldo.c,v 2.50 2008/10/30 15:39:30 roberto Exp roberto $
 ** Stack and Call structure of Lua
 ** See Copyright Notice in lua.h
 */
@@ -390,7 +390,7 @@ void luaD_call (lua_State *L, StkId func, int nResults) {
 static void unroll (lua_State *L) {
   for (;;) {
     Instruction inst;
-    luaV_execute(L);  /* execute up to higher C 'boundary' */
+    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);
       return;  /* coroutine finished normally */
@@ -405,27 +405,38 @@ static void unroll (lua_State *L) {
         break;
       }
       case OP_LE: case OP_LT: case OP_EQ: {
-        int res;
+        int res = !l_isfalse(L->top - 1);
         L->top--;
-        res = !l_isfalse(L->top);
-        /* cannot call metamethod with K operand */
+        /* 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))
-          L->savedpc += GETARG_sBx(*L->savedpc);  /* jump */
-        L->savedpc++;  /* skip jump instruction */
+        if (res != GETARG_A(inst))  /* condition failed? */
+          L->savedpc++;  /* skip jump instruction */
         break;
       }
-      case OP_SETGLOBAL: case OP_SETTABLE:
-        break;  /* nothing to be done */
+      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);
     }
   }
@@ -500,7 +511,6 @@ 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);
-/*printf("yield: %d - %d\n", G(L)->nCcalls, L->baseCcalls);*/
   if (G(L)->nCcalls > L->baseCcalls)
     luaG_runerror(L, "attempt to yield across metamethod/C-call boundary");
   L->base = L->top - nresults;  /* protect stack slots below */

+ 3 - 1
lvm.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lvm.c,v 2.78 2008/10/28 16:53:16 roberto Exp roberto $
+** $Id: lvm.c,v 2.79 2008/10/30 15:39:30 roberto Exp roberto $
 ** Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -271,8 +271,10 @@ void luaV_concat (lua_State *L, int total, int last) {
     StkId top = L->base + last + 1;
     int n = 2;  /* number of elements handled in this pass (at least 2) */
     if (!(ttisstring(top-2) || ttisnumber(top-2)) || !tostring(L, top-1)) {
+      L->top = top;  /* set top to current position (in case of yield) */
       if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT))
         luaG_concaterror(L, top-2, top-1);
+      L->top = L->ci->top;  /* restore top */
     }
     else if (tsvalue(top-1)->len == 0) {  /* second operand is empty? */
       (void)tostring(L, top - 2);  /* result is first operand */ ;