void luaE_freethread (lua_State *L, lua_State *L1) { luaF_close(L1, L1->stack); /* close all upvalues for this thread */ lua_assert(L1->openupval == NULL); luai_userstatefree(L1); freestack(L, L1); luaM_freemem(L, fromstate(L1), state_size(lua_State)); }
LUA_API void lua_close (lua_State *L) { #ifndef LUA_CROSS_COMPILER int oldstate = platform_cpu_set_global_interrupts( PLATFORM_CPU_DISABLE ); lua_sethook( L, NULL, 0, 0 ); lua_crtstate = NULL; lua_pushnil( L ); lua_rawseti( L, LUA_REGISTRYINDEX, LUA_INT_HANDLER_KEY ); elua_int_cleanup(); platform_cpu_set_global_interrupts( oldstate ); linenoise_cleanup( LINENOISE_ID_LUA ); #endif L = G(L)->mainthread; /* only the main thread can be closed */ lua_lock(L); luaF_close(L, L->stack); /* close all upvalues for this thread */ luaC_separateudata(L, 1); /* separate udata that have GC metamethods */ L->errfunc = 0; /* no error function during GC metamethods */ do { /* repeat until no more errors */ L->ci = L->base_ci; L->base = L->top = L->ci->base; L->nCcalls = L->baseCcalls = 0; } while (luaD_rawrunprotected(L, callallgcTM, NULL) != 0); lua_assert(G(L)->tmudata == NULL); luai_userstateclose(L); close_state(L); }
int vm_OP_RETURN(lua_State *L, int a, int b) { TValue *base = L->base; TValue *ra = base + a; if (b != 0) L->top = ra+b-1; if (L->openupval) luaF_close(L, base); b = luaD_poscall(L, ra); return PCRC; }
static void close_state (lua_State *L) { global_State *g = G(L); luaF_close(L, L->stack); /* close all upvalues for this thread */ luaC_freeallobjects(L); /* collect all objects */ luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size); luaZ_freebuffer(L, &g->buff); freestack(L); lua_assert(gettotalbytes(g) == sizeof(LG)); (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */ }
static void resetstack (lua_State *L, int status) { L->ci = L->base_ci; L->base = L->ci->base; luaF_close(L, L->base); /* close eventual pending closures */ luaD_seterrorobj(L, status, L->base); L->nCcalls = L->baseCcalls; L->allowhook = 1; restore_stack_limit(L); L->errfunc = 0; L->errorJmp = NULL; }
static void close_state (lua_State *L) { global_State *g = G(L); luaF_close(L, L->stack); /* close all upvalues for this thread */ luaC_freeallobjects(L); /* collect all objects */ if (g->version) /* closing a fully built state? */ luai_userstateclose(L); luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size); freestack(L); lua_assert(gettotalbytes(g) == sizeof(LG)); (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */ }
static void close_state (lua_State *L) { global_State *g = G(L); luaF_close(L, L->stack); /* close all upvalues for this thread */ luaC_freeall(L); /* collect all objects */ lua_assert(g->rootgc == obj2gco(L)); lua_assert(g->strt.nuse == 0); luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size, TString *); luaZ_freebuffer(L, &g->buff); freestack(L, L); lua_assert(g->totalbytes == sizeof(LG)); (*g->frealloc)(g->ud, fromstate(L), state_size(LG), 0); }
int vm_OP_TAILCALL(lua_State *L, int a, int b) { TValue *func = L->base + a; Closure *cl; CallInfo *ci; StkId st, cur_func; Proto *p; int aux; int tail_recur; if (b != 0) L->top = func+b; /* else previous instruction set top */ /* current function index */ ci = L->ci; cur_func = ci->func; /* check for tail recursive call */ if(gcvalue(func) == gcvalue(cur_func)) { cl = clvalue(func); p = cl->l.p; /* if is not a vararg function. */ tail_recur = !p->is_vararg; L->savedpc = p->code; } else { tail_recur=0; ci->savedpc = L->savedpc; if (!ttisfunction(func)) /* `func' is not a function? */ func = luaD_tryfuncTM(L, func); /* check the `function' tag method */ cl = clvalue(func); #ifndef NDEBUG if(cl->l.isC) { /* can't tailcall into C functions. Causes problems with getfenv() */ luaD_precall(L, func, LUA_MULTRET); vm_OP_RETURN(L, a, 0); return PCRC; } #endif } /* clean up current frame to prepare to tailcall into next function. */ if (L->openupval) luaF_close(L, ci->base); for (aux = 0; func+aux < L->top; aux++) /* move frame down */ setobjs2s(L, cur_func+aux, func+aux); L->top = cur_func+aux; /* JIT function calling it's self. */ if(tail_recur) { for (st = L->top; st < ci->top; st++) setnilvalue(st); return PCRTAILRECUR; } L->base = cur_func; /* point base at new function to call. This is needed by luaD_precall. */ /* unwind stack back to luaD_precall */ return PCRTAILCALL; }
LUA_API void lua_close (lua_State *L) { lua_lock(L); L = G(L)->mainthread; /* only the main thread can be closed */ luaF_close(L, L->stack); /* close all upvalues for this thread */ luaC_separateudata(L); /* separate udata that have GC metamethods */ L->errfunc = 0; /* no error function during GC metamethods */ do { /* repeat until no more errors */ L->ci = L->base_ci; L->base = L->top = L->ci->base; L->nCcalls = 0; } while (luaD_rawrunprotected(L, callallgcTM, NULL) != 0); lua_assert(G(L)->tmudata == NULL); close_state(L); }
static void close_state (lua_State *L) { luaF_close(L, L->stack); /* close all upvalues for this thread */ if (G(L)) { /* close global state */ luaC_sweep(L, 1); /* collect all elements */ lua_assert(G(L)->rootgc == NULL); lua_assert(G(L)->rootudata == NULL); luaS_freeall(L); luaZ_freebuffer(L, &G(L)->buff); } freestack(L, L); if (G(L)) { lua_assert(G(L)->nblocks == sizeof(lua_State) + sizeof(global_State)); luaM_freelem(NULL, G(L)); } freestate(NULL, L); }
/* Note: upvalues are assumed to be after first two slots. */ static void push_LCL(lua_State *L, Proto *pt, Table *env) { Closure *cl; int i, nup = pt->nups; /* Adjust the number of stack slots to the number of upvalues. */ luaL_checkstack(L, nup, "too many upvalues"); lua_settop(L, 2+nup); /* Create a closure from the subroutine prototype. */ cl = luaF_newLclosure(L, nup, env); cl->l.p = pt; /* Allocate new upvalues and close them. */ for (i = 0; i < nup; i++) cl->l.upvals[i] = luaF_findupval(L, L->base + (2+i)); luaF_close(L, L->base + 2); lua_settop(L, 2); /* Remove upvalues. */ setclvalue(L, L->top++, cl); /* Return closure on top of stack. */ luaC_checkGC(L); }
void luaE_freethread (lua_State *L, lua_State *L1) { luaF_close(L1, L1->stack); /* close all upvalues for this thread */ lua_assert(L1->openupval == NULL); freestack(L, L1); freestate(L, L1); }
StkId luaV_execute (lua_State *L) { LClosure *cl; TObject *k; const Instruction *pc; callentry: /* entry point when calling new functions */ L->ci->u.l.pc = &pc; if (L->hookmask & LUA_MASKCALL) luaD_callhook(L, LUA_HOOKCALL, -1); retentry: /* entry point when returning to old functions */ lua_assert(L->ci->state == CI_SAVEDPC || L->ci->state == (CI_SAVEDPC | CI_CALLING)); L->ci->state = CI_HASFRAME; /* activate frame */ pc = L->ci->u.l.savedpc; cl = &clvalue(L->base - 1)->l; k = cl->p->k; /* main loop of interpreter */ for (;;) { const Instruction i = *pc++; StkId base, ra; if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { traceexec(L); if (L->ci->state & CI_YIELD) { /* did hook yield? */ L->ci->u.l.savedpc = pc - 1; L->ci->state = CI_YIELD | CI_SAVEDPC; return NULL; } } /* warning!! several calls may realloc the stack and invalidate `ra' */ base = L->base; ra = RA(i); lua_assert(L->ci->state & CI_HASFRAME); lua_assert(base == L->ci->base); lua_assert(L->top <= L->stack + L->stacksize && L->top >= base); lua_assert(L->top == L->ci->top || GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL || GET_OPCODE(i) == OP_RETURN || GET_OPCODE(i) == OP_SETLISTO); switch (GET_OPCODE(i)) { case OP_MOVE: { setobjs2s(ra, RB(i)); break; } case OP_LOADK: { setobj2s(ra, KBx(i)); break; } case OP_LOADBOOL: { setbvalue(ra, GETARG_B(i)); if (GETARG_C(i)) pc++; /* skip next instruction (if C) */ break; } case OP_LOADNIL: { TObject *rb = RB(i); do { setnilvalue(rb--); } while (rb >= ra); break; } case OP_GETUPVAL: { int b = GETARG_B(i); setobj2s(ra, cl->upvals[b]->v); break; } case OP_GETGLOBAL: { TObject *rb = KBx(i); const TObject *v; lua_assert(ttisstring(rb) && ttistable(&cl->g)); v = luaH_getstr(hvalue(&cl->g), tsvalue(rb)); if (!ttisnil(v)) { setobj2s(ra, v); } else setobj2s(XRA(i), luaV_index(L, &cl->g, rb, 0)); break; } case OP_GETTABLE: { StkId rb = RB(i); TObject *rc = RKC(i); if (ttistable(rb)) { const TObject *v = luaH_get(hvalue(rb), rc); if (!ttisnil(v)) { setobj2s(ra, v); } else setobj2s(XRA(i), luaV_index(L, rb, rc, 0)); } else setobj2s(XRA(i), luaV_getnotable(L, rb, rc, 0)); break; } case OP_SETGLOBAL: { lua_assert(ttisstring(KBx(i)) && ttistable(&cl->g)); luaV_settable(L, &cl->g, KBx(i), ra); break; } case OP_SETUPVAL: { int b = GETARG_B(i); setobj(cl->upvals[b]->v, ra); /* write barrier */ break; } case OP_SETTABLE: { luaV_settable(L, ra, RKB(i), RKC(i)); break; } case OP_NEWTABLE: { int b = GETARG_B(i); b = fb2int(b); sethvalue(ra, luaH_new(L, b, GETARG_C(i))); luaC_checkGC(L); break; } case OP_SELF: { StkId rb = RB(i); TObject *rc = RKC(i); runtime_check(L, ttisstring(rc)); setobjs2s(ra+1, rb); if (ttistable(rb)) { const TObject *v = luaH_getstr(hvalue(rb), tsvalue(rc)); if (!ttisnil(v)) { setobj2s(ra, v); } else setobj2s(XRA(i), luaV_index(L, rb, rc, 0)); } else setobj2s(XRA(i), luaV_getnotable(L, rb, rc, 0)); break; } case OP_ADD: { TObject *rb = RKB(i); TObject *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { setnvalue(ra, nvalue(rb) + nvalue(rc)); } else Arith(L, ra, rb, rc, TM_ADD); break; } case OP_SUB: { TObject *rb = RKB(i); TObject *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { setnvalue(ra, nvalue(rb) - nvalue(rc)); } else Arith(L, ra, rb, rc, TM_SUB); break; } case OP_MUL: { TObject *rb = RKB(i); TObject *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { setnvalue(ra, nvalue(rb) * nvalue(rc)); } else Arith(L, ra, rb, rc, TM_MUL); break; } case OP_DIV: { TObject *rb = RKB(i); TObject *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { setnvalue(ra, nvalue(rb) / nvalue(rc)); } else Arith(L, ra, rb, rc, TM_DIV); break; } case OP_POW: { Arith(L, ra, RKB(i), RKC(i), TM_POW); break; } case OP_UNM: { const TObject *rb = RB(i); TObject temp; if (tonumber(rb, &temp)) { setnvalue(ra, -nvalue(rb)); } else { setnilvalue(&temp); if (!call_binTM(L, RB(i), &temp, ra, TM_UNM)) luaG_aritherror(L, RB(i), &temp); } break; } case OP_NOT: { int res = l_isfalse(RB(i)); /* next assignment may change this value */ setbvalue(ra, res); break; } case OP_CONCAT: { int b = GETARG_B(i); int c = GETARG_C(i); luaV_concat(L, c-b+1, c); /* may change `base' (and `ra') */ base = L->base; setobjs2s(RA(i), base+b); luaC_checkGC(L); break; } case OP_JMP: { dojump(pc, GETARG_sBx(i)); break; } case OP_EQ: { if (equalobj(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; else dojump(pc, GETARG_sBx(*pc) + 1); break; } case OP_LT: { if (luaV_lessthan(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; else dojump(pc, GETARG_sBx(*pc) + 1); break; } case OP_LE: { if (luaV_lessequal(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; else dojump(pc, GETARG_sBx(*pc) + 1); break; } case OP_TEST: { TObject *rb = RB(i); if (l_isfalse(rb) == GETARG_C(i)) pc++; else { setobjs2s(ra, rb); dojump(pc, GETARG_sBx(*pc) + 1); } break; } case OP_CALL: case OP_TAILCALL: { StkId firstResult; int b = GETARG_B(i); 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 > L->top) { /* yield? */ lua_assert(L->ci->state == (CI_C | CI_YIELD)); (L->ci - 1)->u.l.savedpc = pc; (L->ci - 1)->state = CI_SAVEDPC; return NULL; } /* it was a C function (`precall' called it); adjust results */ luaD_poscall(L, nresults, firstResult); if (nresults >= 0) L->top = L->ci->top; } else { /* it is a Lua function */ if (GET_OPCODE(i) == OP_CALL) { /* regular call? */ (L->ci-1)->u.l.savedpc = pc; /* save `pc' to return later */ (L->ci-1)->state = (CI_SAVEDPC | CI_CALLING); } else { /* tail call: put new frame in place of previous one */ int aux; base = (L->ci - 1)->base; /* `luaD_precall' may change the stack */ ra = RA(i); if (L->openupval) luaF_close(L, base); for (aux = 0; ra+aux < L->top; aux++) /* move frame down */ setobjs2s(base+aux-1, ra+aux); (L->ci - 1)->top = L->top = base+aux; /* correct top */ lua_assert(L->ci->state & CI_SAVEDPC); (L->ci - 1)->u.l.savedpc = L->ci->u.l.savedpc; (L->ci - 1)->u.l.tailcalls++; /* one more call lost */ (L->ci - 1)->state = CI_SAVEDPC; L->ci--; /* remove new frame */ L->base = L->ci->base; } goto callentry; } break; } case OP_RETURN: { CallInfo *ci = L->ci - 1; /* previous function frame */ int b = GETARG_B(i); if (b != 0) L->top = ra+b-1; lua_assert(L->ci->state & CI_HASFRAME); if (L->openupval) luaF_close(L, base); L->ci->state = CI_SAVEDPC; /* deactivate current function */ L->ci->u.l.savedpc = pc; /* previous function was running `here'? */ if (!(ci->state & CI_CALLING)) { lua_assert((ci->state & CI_C) || ci->u.l.pc != &pc); return ra; /* no: return */ } else { /* yes: continue its execution */ int nresults; lua_assert(ci->u.l.pc == &pc && ttisfunction(ci->base - 1) && (ci->state & CI_SAVEDPC)); lua_assert(GET_OPCODE(*(ci->u.l.savedpc - 1)) == OP_CALL); nresults = GETARG_C(*(ci->u.l.savedpc - 1)) - 1; luaD_poscall(L, nresults, ra); if (nresults >= 0) L->top = L->ci->top; goto retentry; } } case OP_FORLOOP: { lua_Number step, idx, limit; const TObject *plimit = ra+1; const TObject *pstep = ra+2; if (!ttisnumber(ra)) luaG_runerror(L, "`for' initial value must be a number"); if (!tonumber(plimit, ra+1)) luaG_runerror(L, "`for' limit must be a number"); if (!tonumber(pstep, ra+2)) luaG_runerror(L, "`for' step must be a number"); step = nvalue(pstep); idx = nvalue(ra) + step; /* increment index */ limit = nvalue(plimit); if (step > 0 ? idx <= limit : idx >= limit) { dojump(pc, GETARG_sBx(i)); /* jump back */ chgnvalue(ra, idx); /* update index */ } break; } case OP_TFORLOOP: { int nvar = GETARG_C(i) + 1; StkId cb = ra + nvar + 2; /* call base */ setobjs2s(cb, ra); setobjs2s(cb+1, ra+1); setobjs2s(cb+2, ra+2); L->top = cb+3; /* func. + 2 args (state and index) */ luaD_call(L, cb, nvar); L->top = L->ci->top; ra = XRA(i) + 2; /* final position of first result */ cb = ra + nvar; do { /* move results to proper positions */ nvar--; setobjs2s(ra+nvar, cb+nvar); } while (nvar > 0); if (ttisnil(ra)) /* break loop? */ pc++; /* skip jump (break loop) */ else dojump(pc, GETARG_sBx(*pc) + 1); /* jump back */ break; } case OP_TFORPREP: { /* for compatibility only */ if (ttistable(ra)) { setobjs2s(ra+1, ra); setobj2s(ra, luaH_getstr(hvalue(gt(L)), luaS_new(L, "next"))); } dojump(pc, GETARG_sBx(i)); break; } case OP_SETLIST: case OP_SETLISTO: { int bc; int n; Table *h; runtime_check(L, ttistable(ra)); h = hvalue(ra); bc = GETARG_Bx(i); if (GET_OPCODE(i) == OP_SETLIST) n = (bc&(LFIELDS_PER_FLUSH-1)) + 1; else { n = L->top - ra - 1; L->top = L->ci->top; } bc &= ~(LFIELDS_PER_FLUSH-1); /* bc = bc - bc%FPF */ for (; n > 0; n--) setobj2t(luaH_setnum(L, h, bc+n), ra+n); /* write barrier */ break; } case OP_CLOSE: { luaF_close(L, ra); break; } case OP_CLOSURE: { Proto *p; Closure *ncl; int nup, j; p = cl->p->p[GETARG_Bx(i)]; nup = p->nups; ncl = luaF_newLclosure(L, nup, &cl->g); ncl->l.p = p; for (j=0; j<nup; j++, pc++) { if (GET_OPCODE(*pc) == OP_GETUPVAL) ncl->l.upvals[j] = cl->upvals[GETARG_B(*pc)]; else { lua_assert(GET_OPCODE(*pc) == OP_MOVE); ncl->l.upvals[j] = luaF_findupval(L, base + GETARG_B(*pc)); } } setclvalue(ra, ncl); luaC_checkGC(L); break; } } } }