mirror of
https://github.com/lua/lua
synced 2024-12-24 03:16:50 +03:00
yielding across lua_call (first version)
This commit is contained in:
parent
f9d015523e
commit
ba484b9eb1
22
lapi.c
22
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);
|
||||
}
|
||||
|
||||
|
||||
|
6
lapi.h
6
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
|
||||
|
11
lbaselib.c
11
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);
|
||||
}
|
||||
|
||||
|
||||
|
4
ldebug.c
4
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);
|
||||
}
|
||||
|
105
ldo.c
105
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 */
|
||||
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 */
|
||||
luaV_execute(L);
|
||||
}
|
||||
else { /* 'common' yield */
|
||||
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;
|
||||
|
5
ldo.h
5
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);
|
||||
|
4
lgc.c
4
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);
|
||||
}
|
||||
|
||||
|
||||
|
4
lstate.c
4
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;
|
||||
|
7
lstate.h
7
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;
|
||||
|
30
ltablib.c
30
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 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
if (!lua_isnil(L, -1))
|
||||
return 1;
|
||||
lua_pop(L, 2); /* remove value and result */
|
||||
}
|
||||
return 0;
|
||||
lua_pushnil(L); /* first value */
|
||||
lua_pushnil(L); /* first "return" */
|
||||
return foreachcont(L);
|
||||
}
|
||||
|
||||
|
||||
|
8
lua.h
8
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);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
72
lvm.c
72
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 {
|
||||
|
3
lvm.h
3
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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user