LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { Closure *cl; lua_lock(L); luaC_checkGC(L); api_checknelems(L, n); cl = luaF_newCclosure(L, n); cl->c.f = fn; L->top -= n; while (n--) setobj2n(&cl->c.upvalue[n], L->top+n); setclvalue(L->top, cl); api_incr_top(L); lua_unlock(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); }
LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { int status; Closure *f = NULL; CallInfo *ci = NULL; void *plight = NULL; lua_lock(L); if (*what == '>') { StkId func = L->top - 1; luai_apicheck(L, ttisfunction(func) || ttislightfunction(func)); what++; /* skip the '>' */ if (ttisfunction(func)) f = clvalue(func); else plight = fvalue(func); L->top--; /* pop function */ } else if (ar->i_ci != 0) { /* no tail call? */ ci = L->base_ci + ar->i_ci; lua_assert(ttisfunction(ci->func) || ttislightfunction(ci->func)); if (ttisfunction(ci->func)) f = clvalue(ci->func); else plight = fvalue(ci->func); } status = auxgetinfo(L, what, ar, f, plight, ci); if (strchr(what, 'f')) { if (f != NULL) setclvalue(L, L->top, f) else if (plight != NULL) setfvalue(L->top, plight) else setnilvalue(L->top); incr_top(L); } if (strchr(what, 'L')) collectvalidlines(L, f); lua_unlock(L); return status; }
LUALIB_API int load_compiled_protos(lua_State *L, jit_proto *p) { Closure *cl; Proto *tf; int i; // load compiled lua code. luaC_checkGC(L); set_block_gc(L); /* stop collector during jit function loading. */ tf = load_jit_proto(L, p); #if DUMP_PROTOS luaU_dump_proto(tf,2); #endif cl = luaF_newLclosure(L, tf->nups, hvalue(gt(L))); cl->l.p = tf; for (i = 0; i < tf->nups; i++) /* initialize eventual upvalues */ cl->l.upvals[i] = luaF_newupval(L); setclvalue(L, L->top, cl); incr_top(L); unset_block_gc(L); return 0; }
static void pushclosure(lua_State *L, Closure *closure) { TValue o; setclvalue(L, &o, closure); LIF(A,pushobject)(L, &o); }
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; } } } }
void pushClosure(lua_State *luaState, Closure *closure) { TValue obj; setclvalue(luaState, &obj, closure); pushObject(luaState, &obj); }