static void body (LexState *ls, expdesc *e, int needself, int line) { /* body -> `(' parlist `)' chunk END */ FuncState new_fs; open_func(ls, &new_fs); try { new_fs.f->linedefined = line; checknext(ls, '('); if (needself) { new_localvarliteral(ls, "self", 0); adjustlocalvars(ls, 1); } parlist(ls); checknext(ls, ')'); chunk(ls); new_fs.f->lastlinedefined = ls->linenumber; check_match(ls, TK_END, TK_FUNCTION, line); } catch( ... ) { close_func(ls); // We do not need the proto anymore. new_fs.f->DereferenceGC( ls->L ); throw; } close_func(ls); pushclosure(ls, &new_fs, e); // Terminate the FuncState again. new_fs.f->DereferenceGC( ls->L ); }
static void lll_closure(lua_State* L, LClosure* cl, TValue* base, TValue* ra, int bx) { Proto *p = cl->p->p[bx]; LClosure *ncl = getcached(p, cl->upvals, base); /* cached closure */ if (ncl == NULL) /* no match? */ pushclosure(L, p, cl->upvals, base, ra); /* create a new one */ else setclLvalue(L, ra, ncl); /* push cashed closure */ }
/* The GC is not fond of finding upvalues in tables. We get around this * during persistence using a weakly keyed table, so that the GC doesn't * bother to mark them. This won't work in unpersisting, however, since * if we make the values weak they'll be collected (since nothing else * references them). Our solution, during unpersisting, is to represent * upvalues as dummy functions, each with one upvalue. */ static void boxupval(lua_State *L) { /* ... upval */ LClosure *lcl; UpVal *uv; uv = toupval(L, -1); lua_pop(L, 1); /* ... */ lcl = (LClosure*)luaF_newLclosure(L, 1, &L->_gt); pushclosure(L, (Closure*)lcl); /* ... func */ lcl->p = makefakeproto(L, 1); lcl->upvals[0] = uv; }
static void body (LexState *ls, expdesc *e, int needself, int line) { /* body -> `(' parlist `)' chunk END */ FuncState new_fs; open_func(ls, &new_fs); new_fs.f->lineDefined = line; check(ls, '('); if (needself) create_local(ls, "self"); parlist(ls); check(ls, ')'); chunk(ls); check_match(ls, TK_END, TK_FUNCTION, line); close_func(ls); pushclosure(ls, &new_fs, e); }
static void body (LexState *ls, expdesc *e, int needself, int line) { /* body -> `(' parlist `)' chunk END */ #ifdef LUA_UTILITIES_NET char szFuncName1[256]; char szFuncName2[256]; #endif FuncState new_fs; open_func(ls, &new_fs); new_fs.f->linedefined = line; #ifdef LUA_UTILITIES_NET szFuncName1[0] = 0; szFuncName2[0] = 0; TryGetFunctionName(ls->t.seminfo.ts, szFuncName1, 256); #endif checknext(ls, '('); if (needself) { new_localvarliteral(ls, "self", 0); adjustlocalvars(ls, 1); } parlist(ls); checknext(ls, ')'); chunk(ls); #ifdef LUA_UTILITIES_NET if (szFuncName1[0] == 0) TryGetFunctionName(ls->t.seminfo.ts, szFuncName2, 256); #endif new_fs.f->lastlinedefined = ls->linenumber; check_match(ls, TK_END, TK_FUNCTION, line); close_func(ls); #ifdef LUA_UTILITIES_NET // Use the correct function name based on values obtained if (szFuncName1[0] == 0) GetFunction(szFuncName2, ls, new_fs.f); else GetFunction(szFuncName1, ls, new_fs.f); #endif pushclosure(ls, &new_fs, e); }
static void body (LexState *ls, expdesc *e, int needself, int line) { /* body -> `(' parlist `)' chunk END */ FuncState new_fs; open_func(ls, &new_fs); new_fs.f->linedefined = line; checknext(ls, '('); if (needself) { new_localvarliteral(ls, "self", 0); adjustlocalvars(ls, 1); } parlist(ls); checknext(ls, ')'); chunk(ls); new_fs.f->lastlinedefined = ls->linenumber; check_match(ls, TK_END, TK_FUNCTION, line); close_func(ls); pushclosure(ls, &new_fs, e); }
static void unpersistfunction(int ref, UnpersistInfo *upi) { /* perms reftbl ... */ LClosure *lcl; int i; lu_byte nupvalues; verify(luaZ_read(&upi->zio, &nupvalues, sizeof(lu_byte)) == 0); lcl = (LClosure*)luaF_newLclosure(upi->L, nupvalues, &upi->L->_gt); pushclosure(upi->L, (Closure*)lcl); /* perms reftbl ... func */ /* Put *some* proto in the closure, before the GC can find it */ lcl->p = makefakeproto(upi->L, nupvalues); /* Also, we need to temporarily fill the upvalues */ lua_pushnil(upi->L); /* perms reftbl ... func nil */ for(i=0; i<nupvalues; i++) { lcl->upvals[i] = makeupval(upi->L, -1); } lua_pop(upi->L, 1); /* perms reftbl ... func */ /* I can't see offhand how a function would ever get to be self- * referential, but just in case let's register it early */ registerobject(ref, upi); /* Now that it's safe, we can get the real proto */ unpersist(upi); /* perms reftbl ... func proto? */ lua_assert(lua_type(upi->L, -1) == LUA_TPROTO); /* perms reftbl ... func proto */ lcl->p = toproto(upi->L, -1); lua_pop(upi->L, 1); /* perms reftbl ... func */ for(i=0; i<nupvalues; i++) { /* perms reftbl ... func */ unpersist(upi); /* perms reftbl ... func func2 */ unboxupval(upi->L); /* perms reftbl ... func upval */ lcl->upvals[i] = toupval(upi->L, -1); lua_pop(upi->L, 1); /* perms reftbl ... func */ } /* perms reftbl ... func */ /* Finally, the fenv */ unpersist(upi); /* perms reftbl ... func fenv/nil? */ lua_assert(lua_type(upi->L, -1) == LUA_TNIL || lua_type(upi->L, -1) == LUA_TTABLE); /* perms reftbl ... func fenv/nil */ if(!lua_isnil(upi->L, -1)) { /* perms reftbl ... func fenv */ lua_setfenv(upi->L, -2); /* perms reftbl ... func */ } else { /* perms reftbl ... func nil */ lua_pop(upi->L, 1); /* perms reftbl ... func */ } /* perms reftbl ... func */ }
static void ktap_execute(ktap_state *ks) { int exec_count = 0; ktap_callinfo *ci; ktap_lclosure *cl; ktap_value *k; unsigned int instr, opcode; StkId base; /* stack pointer */ StkId ra; /* register pointer */ int res, nresults; /* temp varible */ ci = ks->ci; newframe: cl = CLVALUE(ci->func); k = cl->p->k; base = ci->u.l.base; mainloop: /* main loop of interpreter */ /* dead loop detaction */ if (exec_count++ == 10000) { if (G(ks)->mainthread != ks) { kp_error(ks, "non-mainthread executing too much, " "please try to enlarge execution limit\n"); return; } cond_resched(); if (signal_pending(current)) { flush_signals(current); return; } exec_count = 0; } instr = *(ci->u.l.savedpc++); opcode = GET_OPCODE(instr); /* ra is target register */ ra = RA(instr); switch (opcode) { case OP_MOVE: setobj(ra, base + GETARG_B(instr)); break; case OP_LOADK: setobj(ra, k + GETARG_Bx(instr)); break; case OP_LOADKX: setobj(ra, k + GETARG_Ax(*ci->u.l.savedpc++)); break; case OP_LOADBOOL: setbvalue(ra, GETARG_B(instr)); if (GETARG_C(instr)) ci->u.l.savedpc++; break; case OP_LOADNIL: { int b = GETARG_B(instr); do { setnilvalue(ra++); } while (b--); break; } case OP_GETUPVAL: { int b = GETARG_B(instr); setobj(ra, cl->upvals[b]->v); break; } case OP_GETTABUP: { int b = GETARG_B(instr); gettable(ks, cl->upvals[b]->v, RKC(instr), ra); base = ci->u.l.base; break; } case OP_GETTABLE: gettable(ks, RB(instr), RKC(instr), ra); base = ci->u.l.base; break; case OP_SETTABUP: { int a = GETARG_A(instr); settable(ks, cl->upvals[a]->v, RKB(instr), RKC(instr)); base = ci->u.l.base; break; } case OP_SETUPVAL: { ktap_upval *uv = cl->upvals[GETARG_B(instr)]; setobj(uv->v, ra); break; } case OP_SETTABLE: settable(ks, ra, RKB(instr), RKC(instr)); base = ci->u.l.base; break; case OP_NEWTABLE: { int b = GETARG_B(instr); int c = GETARG_C(instr); ktap_table *t = kp_table_new(ks); sethvalue(ra, t); if (b != 0 || c != 0) kp_table_resize(ks, t, fb2int(b), fb2int(c)); break; } case OP_SELF: { StkId rb = RB(instr); setobj(ra+1, rb); gettable(ks, rb, RKC(instr), ra); base = ci->u.l.base; break; } case OP_ADD: arith_op(ks, NUMADD); break; case OP_SUB: arith_op(ks, NUMSUB); break; case OP_MUL: arith_op(ks, NUMMUL); break; case OP_DIV: /* divide 0 checking */ if (!nvalue(RKC(instr))) { kp_error(ks, "divide 0 arith operation\n"); return; } arith_op(ks, NUMDIV); break; case OP_MOD: /* divide 0 checking */ if (!nvalue(RKC(instr))) { kp_error(ks, "mod 0 arith operation\n"); return; } arith_op(ks, NUMMOD); break; case OP_POW: kp_error(ks, "ktap don't support pow arith in kernel\n"); return; case OP_UNM: { ktap_value *rb = RB(instr); if (ttisnumber(rb)) { ktap_number nb = nvalue(rb); setnvalue(ra, NUMUNM(nb)); } break; } case OP_NOT: res = isfalse(RB(instr)); setbvalue(ra, res); break; case OP_LEN: { int len = kp_objlen(ks, RB(instr)); if (len < 0) return; setnvalue(ra, len); break; } case OP_CONCAT: { int b = GETARG_B(instr); int c = GETARG_C(instr); ktap_concat(ks, b, c); break; } case OP_JMP: dojump(ci, instr, 0); break; case OP_EQ: { ktap_value *rb = RKB(instr); ktap_value *rc = RKC(instr); if ((int)equalobj(ks, rb, rc) != GETARG_A(instr)) ci->u.l.savedpc++; else donextjump(ci); base = ci->u.l.base; break; } case OP_LT: if (lessthan(ks, RKB(instr), RKC(instr)) != GETARG_A(instr)) ci->u.l.savedpc++; else donextjump(ci); base = ci->u.l.base; break; case OP_LE: if (lessequal(ks, RKB(instr), RKC(instr)) != GETARG_A(instr)) ci->u.l.savedpc++; else donextjump(ci); base = ci->u.l.base; break; case OP_TEST: if (GETARG_C(instr) ? isfalse(ra) : !isfalse(ra)) ci->u.l.savedpc++; else donextjump(ci); break; case OP_TESTSET: { ktap_value *rb = RB(instr); if (GETARG_C(instr) ? isfalse(rb) : !isfalse(rb)) ci->u.l.savedpc++; else { setobj(ra, rb); donextjump(ci); } break; } case OP_CALL: { int b = GETARG_B(instr); int ret; nresults = GETARG_C(instr) - 1; if (b != 0) ks->top = ra + b; ret = precall(ks, ra, nresults); if (ret) { /* C function */ if (nresults >= 0) ks->top = ci->top; base = ci->u.l.base; break; } else { /* ktap function */ ci = ks->ci; /* this flag is used for return time, see OP_RETURN */ ci->callstatus |= CIST_REENTRY; goto newframe; } break; } case OP_TAILCALL: { int b = GETARG_B(instr); if (b != 0) ks->top = ra+b; if (precall(ks, ra, -1)) /* C function? */ base = ci->u.l.base; else { int aux; /* * tail call: put called frame (n) in place of * caller one (o) */ ktap_callinfo *nci = ks->ci; /* called frame */ ktap_callinfo *oci = nci->prev; /* caller frame */ StkId nfunc = nci->func; /* called function */ StkId ofunc = oci->func; /* caller function */ /* last stack slot filled by 'precall' */ StkId lim = nci->u.l.base + CLVALUE(nfunc)->p->numparams; /* close all upvalues from previous call */ if (cl->p->sizep > 0) function_close(ks, oci->u.l.base); /* move new frame into old one */ for (aux = 0; nfunc + aux < lim; aux++) setobj(ofunc + aux, nfunc + aux); /* correct base */ oci->u.l.base = ofunc + (nci->u.l.base - nfunc); /* correct top */ oci->top = ks->top = ofunc + (ks->top - nfunc); oci->u.l.savedpc = nci->u.l.savedpc; /* remove new frame */ ci = ks->ci = oci; /* restart ktap_execute over new ktap function */ goto newframe; } break; } case OP_RETURN: { int b = GETARG_B(instr); if (b != 0) ks->top = ra+b-1; if (cl->p->sizep > 0) function_close(ks, base); b = poscall(ks, ra); /* if it's called from external invocation, just return */ if (!(ci->callstatus & CIST_REENTRY)) return; ci = ks->ci; if (b) ks->top = ci->top; goto newframe; } case OP_FORLOOP: { ktap_number step = nvalue(ra+2); /* increment index */ ktap_number idx = NUMADD(nvalue(ra), step); ktap_number limit = nvalue(ra+1); if (NUMLT(0, step) ? NUMLE(idx, limit) : NUMLE(limit, idx)) { ci->u.l.savedpc += GETARG_sBx(instr); /* jump back */ setnvalue(ra, idx); /* update internal index... */ setnvalue(ra+3, idx); /* ...and external index */ } break; } case OP_FORPREP: { const ktap_value *init = ra; const ktap_value *plimit = ra + 1; const ktap_value *pstep = ra + 2; if (!ktap_tonumber(init, ra)) { kp_error(ks, KTAP_QL("for") " initial value must be a number\n"); return; } else if (!ktap_tonumber(plimit, ra + 1)) { kp_error(ks, KTAP_QL("for") " limit must be a number\n"); return; } else if (!ktap_tonumber(pstep, ra + 2)) { kp_error(ks, KTAP_QL("for") " step must be a number\n"); return; } setnvalue(ra, NUMSUB(nvalue(ra), nvalue(pstep))); ci->u.l.savedpc += GETARG_sBx(instr); break; } case OP_TFORCALL: { StkId cb = ra + 3; /* call base */ setobj(cb + 2, ra + 2); setobj(cb + 1, ra + 1); setobj(cb, ra); ks->top = cb + 3; /* func. + 2 args (state and index) */ kp_call(ks, cb, GETARG_C(instr)); base = ci->u.l.base; ks->top = ci->top; instr = *(ci->u.l.savedpc++); /* go to next instruction */ ra = RA(instr); } /*go through */ case OP_TFORLOOP: if (!ttisnil(ra + 1)) { /* continue loop? */ setobj(ra, ra + 1); /* save control variable */ ci->u.l.savedpc += GETARG_sBx(instr); /* jump back */ } break; case OP_SETLIST: { int n = GETARG_B(instr); int c = GETARG_C(instr); int last; ktap_table *h; if (n == 0) n = (int)(ks->top - ra) - 1; if (c == 0) c = GETARG_Ax(*ci->u.l.savedpc++); h = hvalue(ra); last = ((c - 1) * LFIELDS_PER_FLUSH) + n; if (last > h->sizearray) /* needs more space? */ kp_table_resizearray(ks, h, last); for (; n > 0; n--) { ktap_value *val = ra+n; kp_table_setint(ks, h, last--, val); } /* correct top (in case of previous open call) */ ks->top = ci->top; break; } case OP_CLOSURE: { /* need to use closure cache? (multithread contention issue)*/ ktap_proto *p = cl->p->p[GETARG_Bx(instr)]; pushclosure(ks, p, cl->upvals, base, ra); break; } case OP_VARARG: { int b = GETARG_B(instr) - 1; int j; int n = (int)(base - ci->func) - cl->p->numparams - 1; if (b < 0) { /* B == 0? */ b = n; /* get all var. arguments */ checkstack(ks, n); /* previous call may change the stack */ ra = RA(instr); ks->top = ra + n; } for (j = 0; j < b; j++) { if (j < n) { setobj(ra + j, base - n + j); } else setnilvalue(ra + j); } break; } case OP_EXTRAARG: return; case OP_EVENT: { struct ktap_event *e = ks->current_event; if (unlikely(!e)) { kp_error(ks, "invalid event context\n"); return; } setevalue(ra, e); break; } case OP_EVENTNAME: { struct ktap_event *e = ks->current_event; if (unlikely(!e)) { kp_error(ks, "invalid event context\n"); return; } setsvalue(ra, kp_tstring_new(ks, e->call->name)); break; } case OP_EVENTARG: if (unlikely(!ks->current_event)) { kp_error(ks, "invalid event context\n"); return; } kp_event_getarg(ks, ra, GETARG_B(instr)); break; case OP_LOAD_GLOBAL: { ktap_value *cfunc = cfunction_cache_get(ks, GETARG_C(instr)); setobj(ra, cfunc); } break; case OP_EXIT: return; } goto mainloop; }