rlm@1: /* rlm@1: ** $Id: ldo.c,v 2.38.1.3 2008/01/18 22:31:22 roberto Exp $ rlm@1: ** Stack and Call structure of Lua rlm@1: ** See Copyright Notice in lua.h rlm@1: */ rlm@1: rlm@1: rlm@1: #include rlm@1: #include rlm@1: #include rlm@1: rlm@1: #define ldo_c rlm@1: #define LUA_CORE rlm@1: rlm@1: #include "lua.h" rlm@1: rlm@1: #include "ldebug.h" rlm@1: #include "ldo.h" rlm@1: #include "lfunc.h" rlm@1: #include "lgc.h" rlm@1: #include "lmem.h" rlm@1: #include "lobject.h" rlm@1: #include "lopcodes.h" rlm@1: #include "lparser.h" rlm@1: #include "lstate.h" rlm@1: #include "lstring.h" rlm@1: #include "ltable.h" rlm@1: #include "ltm.h" rlm@1: #include "lundump.h" rlm@1: #include "lvm.h" rlm@1: #include "lzio.h" rlm@1: rlm@1: rlm@1: rlm@1: rlm@1: /* rlm@1: ** {====================================================== rlm@1: ** Error-recovery functions rlm@1: ** ======================================================= rlm@1: */ rlm@1: rlm@1: rlm@1: /* chain list of long jump buffers */ rlm@1: struct lua_longjmp { rlm@1: struct lua_longjmp *previous; rlm@1: luai_jmpbuf b; rlm@1: volatile int status; /* error code */ rlm@1: }; rlm@1: rlm@1: rlm@1: void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) { rlm@1: switch (errcode) { rlm@1: case LUA_ERRMEM: { rlm@1: setsvalue2s(L, oldtop, luaS_newliteral(L, MEMERRMSG)); rlm@1: break; rlm@1: } rlm@1: case LUA_ERRERR: { rlm@1: setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); rlm@1: break; rlm@1: } rlm@1: case LUA_ERRSYNTAX: rlm@1: case LUA_ERRRUN: { rlm@1: setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ rlm@1: break; rlm@1: } rlm@1: } rlm@1: L->top = oldtop + 1; rlm@1: } rlm@1: rlm@1: rlm@1: static void restore_stack_limit (lua_State *L) { rlm@1: lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1); rlm@1: if (L->size_ci > LUAI_MAXCALLS) { /* there was an overflow? */ rlm@1: int inuse = cast_int(L->ci - L->base_ci); rlm@1: if (inuse + 1 < LUAI_MAXCALLS) /* can `undo' overflow? */ rlm@1: luaD_reallocCI(L, LUAI_MAXCALLS); rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: static void resetstack (lua_State *L, int status) { rlm@1: L->ci = L->base_ci; rlm@1: L->base = L->ci->base; rlm@1: luaF_close(L, L->base); /* close eventual pending closures */ rlm@1: luaD_seterrorobj(L, status, L->base); rlm@1: L->nCcalls = L->baseCcalls; rlm@1: L->allowhook = 1; rlm@1: restore_stack_limit(L); rlm@1: L->errfunc = 0; rlm@1: L->errorJmp = NULL; rlm@1: } rlm@1: rlm@1: rlm@1: void luaD_throw (lua_State *L, int errcode) { rlm@1: if (L->errorJmp) { rlm@1: L->errorJmp->status = errcode; rlm@1: LUAI_THROW(L, L->errorJmp); rlm@1: } rlm@1: else { rlm@1: L->status = cast_byte(errcode); rlm@1: if (G(L)->panic) { rlm@1: resetstack(L, errcode); rlm@1: lua_unlock(L); rlm@1: G(L)->panic(L); rlm@1: } rlm@1: exit(EXIT_FAILURE); rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { rlm@1: struct lua_longjmp lj; rlm@1: lj.status = 0; rlm@1: lj.previous = L->errorJmp; /* chain new error handler */ rlm@1: L->errorJmp = &lj; rlm@1: LUAI_TRY(L, &lj, rlm@1: (*f)(L, ud); rlm@1: ); rlm@1: L->errorJmp = lj.previous; /* restore old error handler */ rlm@1: return lj.status; rlm@1: } rlm@1: rlm@1: /* }====================================================== */ rlm@1: rlm@1: rlm@1: static void correctstack (lua_State *L, TValue *oldstack) { rlm@1: CallInfo *ci; rlm@1: GCObject *up; rlm@1: L->top = (L->top - oldstack) + L->stack; rlm@1: for (up = L->openupval; up != NULL; up = up->gch.next) rlm@1: gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack; rlm@1: for (ci = L->base_ci; ci <= L->ci; ci++) { rlm@1: ci->top = (ci->top - oldstack) + L->stack; rlm@1: ci->base = (ci->base - oldstack) + L->stack; rlm@1: ci->func = (ci->func - oldstack) + L->stack; rlm@1: } rlm@1: L->base = (L->base - oldstack) + L->stack; rlm@1: } rlm@1: rlm@1: rlm@1: void luaD_reallocstack (lua_State *L, int newsize) { rlm@1: TValue *oldstack = L->stack; rlm@1: int realsize = newsize + 1 + EXTRA_STACK; rlm@1: lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK - 1); rlm@1: luaM_reallocvector(L, L->stack, L->stacksize, realsize, TValue); rlm@1: L->stacksize = realsize; rlm@1: L->stack_last = L->stack+newsize; rlm@1: correctstack(L, oldstack); rlm@1: } rlm@1: rlm@1: rlm@1: void luaD_reallocCI (lua_State *L, int newsize) { rlm@1: CallInfo *oldci = L->base_ci; rlm@1: luaM_reallocvector(L, L->base_ci, L->size_ci, newsize, CallInfo); rlm@1: L->size_ci = newsize; rlm@1: L->ci = (L->ci - oldci) + L->base_ci; rlm@1: L->end_ci = L->base_ci + L->size_ci - 1; rlm@1: } rlm@1: rlm@1: rlm@1: void luaD_growstack (lua_State *L, int n) { rlm@1: if (n <= L->stacksize) /* double size is enough? */ rlm@1: luaD_reallocstack(L, 2*L->stacksize); rlm@1: else rlm@1: luaD_reallocstack(L, L->stacksize + n); rlm@1: } rlm@1: rlm@1: rlm@1: static CallInfo *growCI (lua_State *L) { rlm@1: if (L->size_ci > LUAI_MAXCALLS) /* overflow while handling overflow? */ rlm@1: luaD_throw(L, LUA_ERRERR); rlm@1: else { rlm@1: luaD_reallocCI(L, 2*L->size_ci); rlm@1: if (L->size_ci > LUAI_MAXCALLS) rlm@1: luaG_runerror(L, "stack overflow"); rlm@1: } rlm@1: return ++L->ci; rlm@1: } rlm@1: rlm@1: rlm@1: void luaD_callhook (lua_State *L, int event, int line) { rlm@1: lua_Hook hook = L->hook; rlm@1: if (hook && L->allowhook) { rlm@1: ptrdiff_t top = savestack(L, L->top); rlm@1: ptrdiff_t ci_top = savestack(L, L->ci->top); rlm@1: lua_Debug ar; rlm@1: ar.event = event; rlm@1: ar.currentline = line; rlm@1: if (event == LUA_HOOKTAILRET) rlm@1: ar.i_ci = 0; /* tail call; no debug information about it */ rlm@1: else rlm@1: ar.i_ci = cast_int(L->ci - L->base_ci); rlm@1: luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ rlm@1: L->ci->top = L->top + LUA_MINSTACK; rlm@1: lua_assert(L->ci->top <= L->stack_last); rlm@1: L->allowhook = 0; /* cannot call hooks inside a hook */ rlm@1: lua_unlock(L); rlm@1: (*hook)(L, &ar); rlm@1: lua_lock(L); rlm@1: lua_assert(!L->allowhook); rlm@1: L->allowhook = 1; rlm@1: L->ci->top = restorestack(L, ci_top); rlm@1: L->top = restorestack(L, top); rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: static StkId adjust_varargs (lua_State *L, Proto *p, int actual) { rlm@1: int i; rlm@1: int nfixargs = p->numparams; rlm@1: Table *htab = NULL; rlm@1: StkId base, fixed; rlm@1: for (; actual < nfixargs; ++actual) rlm@1: setnilvalue(L->top++); rlm@1: #if defined(LUA_COMPAT_VARARG) rlm@1: if (p->is_vararg & VARARG_NEEDSARG) { /* compat. with old-style vararg? */ rlm@1: int nvar = actual - nfixargs; /* number of extra arguments */ rlm@1: lua_assert(p->is_vararg & VARARG_HASARG); rlm@1: luaC_checkGC(L); rlm@1: htab = luaH_new(L, nvar, 1); /* create `arg' table */ rlm@1: for (i=0; itop - nvar + i); rlm@1: /* store counter in field `n' */ rlm@1: setnvalue(luaH_setstr(L, htab, luaS_newliteral(L, "n")), cast_num(nvar)); rlm@1: } rlm@1: #endif rlm@1: /* move fixed parameters to final position */ rlm@1: fixed = L->top - actual; /* first fixed argument */ rlm@1: base = L->top; /* final position of first argument */ rlm@1: for (i=0; itop++, fixed+i); rlm@1: setnilvalue(fixed+i); rlm@1: } rlm@1: /* add `arg' parameter */ rlm@1: if (htab) { rlm@1: sethvalue(L, L->top++, htab); rlm@1: lua_assert(iswhite(obj2gco(htab))); rlm@1: } rlm@1: return base; rlm@1: } rlm@1: rlm@1: rlm@1: static StkId tryfuncTM (lua_State *L, StkId func) { rlm@1: const TValue *tm = luaT_gettmbyobj(L, func, TM_CALL); rlm@1: StkId p; rlm@1: ptrdiff_t funcr = savestack(L, func); rlm@1: if (!ttisfunction(tm)) rlm@1: luaG_typeerror(L, func, "call"); rlm@1: /* Open a hole inside the stack at `func' */ rlm@1: for (p = L->top; p > func; p--) setobjs2s(L, p, p-1); rlm@1: incr_top(L); rlm@1: func = restorestack(L, funcr); /* previous call may change stack */ rlm@1: setobj2s(L, func, tm); /* tag method is the new function to be called */ rlm@1: return func; rlm@1: } rlm@1: rlm@1: rlm@1: rlm@1: #define inc_ci(L) \ rlm@1: ((L->ci == L->end_ci) ? growCI(L) : \ rlm@1: (condhardstacktests(luaD_reallocCI(L, L->size_ci)), ++L->ci)) rlm@1: rlm@1: rlm@1: int luaD_precall (lua_State *L, StkId func, int nresults) { rlm@1: LClosure *cl; rlm@1: ptrdiff_t funcr; rlm@1: if (!ttisfunction(func)) /* `func' is not a function? */ rlm@1: func = tryfuncTM(L, func); /* check the `function' tag method */ rlm@1: funcr = savestack(L, func); rlm@1: cl = &clvalue(func)->l; rlm@1: L->ci->savedpc = L->savedpc; rlm@1: if (!cl->isC) { /* Lua function? prepare its call */ rlm@1: CallInfo *ci; rlm@1: StkId st, base; rlm@1: Proto *p = cl->p; rlm@1: luaD_checkstack(L, p->maxstacksize); rlm@1: func = restorestack(L, funcr); rlm@1: if (!p->is_vararg) { /* no varargs? */ rlm@1: base = func + 1; rlm@1: if (L->top > base + p->numparams) rlm@1: L->top = base + p->numparams; rlm@1: } rlm@1: else { /* vararg function */ rlm@1: int nargs = cast_int(L->top - func) - 1; rlm@1: base = adjust_varargs(L, p, nargs); rlm@1: func = restorestack(L, funcr); /* previous call may change the stack */ rlm@1: } rlm@1: ci = inc_ci(L); /* now `enter' new function */ rlm@1: ci->func = func; rlm@1: L->base = ci->base = base; rlm@1: ci->top = L->base + p->maxstacksize; rlm@1: lua_assert(ci->top <= L->stack_last); rlm@1: L->savedpc = p->code; /* starting point */ rlm@1: ci->tailcalls = 0; rlm@1: ci->nresults = nresults; rlm@1: for (st = L->top; st < ci->top; st++) rlm@1: setnilvalue(st); rlm@1: L->top = ci->top; rlm@1: if (L->hookmask & LUA_MASKCALL) { rlm@1: L->savedpc++; /* hooks assume 'pc' is already incremented */ rlm@1: luaD_callhook(L, LUA_HOOKCALL, -1); rlm@1: L->savedpc--; /* correct 'pc' */ rlm@1: } rlm@1: return PCRLUA; rlm@1: } rlm@1: else { /* if is a C function, call it */ rlm@1: CallInfo *ci; rlm@1: int n; rlm@1: luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ rlm@1: ci = inc_ci(L); /* now `enter' new function */ rlm@1: ci->func = restorestack(L, funcr); rlm@1: L->base = ci->base = ci->func + 1; rlm@1: ci->top = L->top + LUA_MINSTACK; rlm@1: lua_assert(ci->top <= L->stack_last); rlm@1: ci->nresults = nresults; rlm@1: if (L->hookmask & LUA_MASKCALL) rlm@1: luaD_callhook(L, LUA_HOOKCALL, -1); rlm@1: lua_unlock(L); rlm@1: n = (*curr_func(L)->c.f)(L); /* do the actual call */ rlm@1: lua_lock(L); rlm@1: if (n < 0) /* yielding? */ rlm@1: return PCRYIELD; rlm@1: else { rlm@1: luaD_poscall(L, L->top - n); rlm@1: return PCRC; rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: static StkId callrethooks (lua_State *L, StkId firstResult) { rlm@1: ptrdiff_t fr = savestack(L, firstResult); /* next call may change stack */ rlm@1: luaD_callhook(L, LUA_HOOKRET, -1); rlm@1: if (f_isLua(L->ci)) { /* Lua function? */ rlm@1: while ((L->hookmask & LUA_MASKRET) && L->ci->tailcalls--) /* tail calls */ rlm@1: luaD_callhook(L, LUA_HOOKTAILRET, -1); rlm@1: } rlm@1: return restorestack(L, fr); rlm@1: } rlm@1: rlm@1: rlm@1: int luaD_poscall (lua_State *L, StkId firstResult) { rlm@1: StkId res; rlm@1: int wanted, i; rlm@1: CallInfo *ci; rlm@1: if (L->hookmask & LUA_MASKRET) rlm@1: firstResult = callrethooks(L, firstResult); rlm@1: ci = L->ci--; rlm@1: res = ci->func; /* res == final position of 1st result */ rlm@1: wanted = ci->nresults; rlm@1: L->base = (ci - 1)->base; /* restore base */ rlm@1: L->savedpc = (ci - 1)->savedpc; /* restore savedpc */ rlm@1: /* move results to correct place */ rlm@1: for (i = wanted; i != 0 && firstResult < L->top; i--) rlm@1: setobjs2s(L, res++, firstResult++); rlm@1: while (i-- > 0) rlm@1: setnilvalue(res++); rlm@1: L->top = res; rlm@1: return (wanted - LUA_MULTRET); /* 0 iff wanted == LUA_MULTRET */ rlm@1: } rlm@1: rlm@1: rlm@1: /* rlm@1: ** Call a function (C or Lua). The function to be called is at *func. rlm@1: ** The arguments are on the stack, right after the function. rlm@1: ** When returns, all the results are on the stack, starting at the original rlm@1: ** function position. rlm@1: */ rlm@1: void luaD_call (lua_State *L, StkId func, int nResults) { rlm@1: if (++L->nCcalls >= LUAI_MAXCCALLS) { rlm@1: if (L->nCcalls == LUAI_MAXCCALLS) rlm@1: luaG_runerror(L, "C stack overflow"); rlm@1: else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) rlm@1: luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ rlm@1: } rlm@1: if (luaD_precall(L, func, nResults) == PCRLUA) /* is a Lua function? */ rlm@1: luaV_execute(L, 1); /* call it */ rlm@1: L->nCcalls--; rlm@1: luaC_checkGC(L); rlm@1: } rlm@1: rlm@1: rlm@1: static void resume (lua_State *L, void *ud) { rlm@1: StkId firstArg = cast(StkId, ud); rlm@1: CallInfo *ci = L->ci; rlm@1: if (L->status == 0) { /* start coroutine? */ rlm@1: lua_assert(ci == L->base_ci && firstArg > L->base); rlm@1: if (luaD_precall(L, firstArg - 1, LUA_MULTRET) != PCRLUA) rlm@1: return; rlm@1: } rlm@1: else { /* resuming from previous yield */ rlm@1: lua_assert(L->status == LUA_YIELD); rlm@1: L->status = 0; rlm@1: if (!f_isLua(ci)) { /* `common' yield? */ rlm@1: /* finish interrupted execution of `OP_CALL' */ rlm@1: lua_assert(GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_CALL || rlm@1: GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_TAILCALL); rlm@1: if (luaD_poscall(L, firstArg)) /* complete it... */ rlm@1: L->top = L->ci->top; /* and correct top if not multiple results */ rlm@1: } rlm@1: else /* yielded inside a hook: just continue its execution */ rlm@1: L->base = L->ci->base; rlm@1: } rlm@1: luaV_execute(L, cast_int(L->ci - L->base_ci)); rlm@1: } rlm@1: rlm@1: rlm@1: static int resume_error (lua_State *L, const char *msg) { rlm@1: L->top = L->ci->base; rlm@1: setsvalue2s(L, L->top, luaS_new(L, msg)); rlm@1: incr_top(L); rlm@1: lua_unlock(L); rlm@1: return LUA_ERRRUN; rlm@1: } rlm@1: rlm@1: rlm@1: LUA_API int lua_resume (lua_State *L, int nargs) { rlm@1: int status; rlm@1: lua_lock(L); rlm@1: if (L->status != LUA_YIELD && (L->status != 0 || L->ci != L->base_ci)) rlm@1: return resume_error(L, "cannot resume non-suspended coroutine"); rlm@1: if (L->nCcalls >= LUAI_MAXCCALLS) rlm@1: return resume_error(L, "C stack overflow"); rlm@1: luai_userstateresume(L, nargs); rlm@1: lua_assert(L->errfunc == 0); rlm@1: L->baseCcalls = ++L->nCcalls; rlm@1: status = luaD_rawrunprotected(L, resume, L->top - nargs); rlm@1: if (status != 0) { /* error? */ rlm@1: L->status = cast_byte(status); /* mark thread as `dead' */ rlm@1: luaD_seterrorobj(L, status, L->top); rlm@1: L->ci->top = L->top; rlm@1: } rlm@1: else { rlm@1: lua_assert(L->nCcalls == L->baseCcalls); rlm@1: status = L->status; rlm@1: } rlm@1: --L->nCcalls; rlm@1: lua_unlock(L); rlm@1: return status; rlm@1: } rlm@1: rlm@1: rlm@1: LUA_API int lua_yield (lua_State *L, int nresults) { rlm@1: luai_userstateyield(L, nresults); rlm@1: lua_lock(L); rlm@1: if (L->nCcalls > L->baseCcalls) rlm@1: luaG_runerror(L, "attempt to yield across metamethod/C-call boundary"); rlm@1: L->base = L->top - nresults; /* protect stack slots below */ rlm@1: L->status = LUA_YIELD; rlm@1: lua_unlock(L); rlm@1: return -1; rlm@1: } rlm@1: rlm@1: rlm@1: int luaD_pcall (lua_State *L, Pfunc func, void *u, rlm@1: ptrdiff_t old_top, ptrdiff_t ef) { rlm@1: int status; rlm@1: unsigned short oldnCcalls = L->nCcalls; rlm@1: ptrdiff_t old_ci = saveci(L, L->ci); rlm@1: lu_byte old_allowhooks = L->allowhook; rlm@1: ptrdiff_t old_errfunc = L->errfunc; rlm@1: L->errfunc = ef; rlm@1: status = luaD_rawrunprotected(L, func, u); rlm@1: if (status != 0) { /* an error occurred? */ rlm@1: StkId oldtop = restorestack(L, old_top); rlm@1: luaF_close(L, oldtop); /* close eventual pending closures */ rlm@1: luaD_seterrorobj(L, status, oldtop); rlm@1: L->nCcalls = oldnCcalls; rlm@1: L->ci = restoreci(L, old_ci); rlm@1: L->base = L->ci->base; rlm@1: L->savedpc = L->ci->savedpc; rlm@1: L->allowhook = old_allowhooks; rlm@1: restore_stack_limit(L); rlm@1: } rlm@1: L->errfunc = old_errfunc; rlm@1: return status; rlm@1: } rlm@1: rlm@1: rlm@1: rlm@1: /* rlm@1: ** Execute a protected parser. rlm@1: */ rlm@1: struct SParser { /* data to `f_parser' */ rlm@1: ZIO *z; rlm@1: Mbuffer buff; /* buffer to be used by the scanner */ rlm@1: const char *name; rlm@1: }; rlm@1: rlm@1: static void f_parser (lua_State *L, void *ud) { rlm@1: int i; rlm@1: Proto *tf; rlm@1: Closure *cl; rlm@1: struct SParser *p = cast(struct SParser *, ud); rlm@1: int c = luaZ_lookahead(p->z); rlm@1: luaC_checkGC(L); rlm@1: tf = ((c == LUA_SIGNATURE[0]) ? luaU_undump : luaY_parser)(L, p->z, rlm@1: &p->buff, p->name); rlm@1: cl = luaF_newLclosure(L, tf->nups, hvalue(gt(L))); rlm@1: cl->l.p = tf; rlm@1: for (i = 0; i < tf->nups; i++) /* initialize eventual upvalues */ rlm@1: cl->l.upvals[i] = luaF_newupval(L); rlm@1: setclvalue(L, L->top, cl); rlm@1: incr_top(L); rlm@1: } rlm@1: rlm@1: rlm@1: int luaD_protectedparser (lua_State *L, ZIO *z, const char *name) { rlm@1: struct SParser p; rlm@1: int status; rlm@1: p.z = z; p.name = name; rlm@1: luaZ_initbuffer(L, &p.buff); rlm@1: status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc); rlm@1: luaZ_freebuffer(L, &p.buff); rlm@1: return status; rlm@1: } rlm@1: rlm@1: