LUA_API int lua_getinfo(lua_State* L, const char* what, lua_Debug* ar) { int status; Closure* f = NULL; CallInfo* ci = NULL; lua_lock(L); if (*what == '>') { StkId func = L->top - 1; luai_apicheck(L, ttisfunction(func)); what++; /* skip the '>' */ f = clvalue(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)); f = clvalue(ci->func); } status = auxgetinfo(L, what, ar, f, ci); if (strchr(what, 'f')) { if (f == NULL) setnilvalue(L->top); else setclvalue(L, L->top, f); incr_top(L); } if (strchr(what, 'L')) collectvalidlines(L, f); lua_unlock(L); return status; }
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; }
int luaO_equalval (const TObject *t1, const TObject *t2) { switch (ttype(t1)) { case TAG_NUMBER: return nvalue(t1) == nvalue(t2); case TAG_STRING: case TAG_USERDATA: return svalue(t1) == svalue(t2); case TAG_TABLE: return avalue(t1) == avalue(t2); case TAG_CCLOSURE: case TAG_LCLOSURE: return clvalue(t1) == clvalue(t2); default: LUA_ASSERT(L, ttype(t1) == TAG_NIL, "invalid type"); return 1; /* TAG_NIL */ } }
static void setnormalized (TObject *d, const TObject *s) { if (ttype(s) == LUA_TMARK) { clvalue(d) = infovalue(s)->func; ttype(d) = LUA_TFUNCTION; } else *d = *s; }
static int lua_combine( lua_State* L) { int n = lua_gettop( L); /* Number of functions to combine */ if( 1 == n) { return 1; /* Only one function, nothing to combine */ } else { int i, pc = 3*n + 1; Proto* f = luaF_newproto( L); setptvalue2s( L,L->top,f); incr_top( L); f->source = luaS_newliteral( L,"=(combiner)"); f->maxstacksize = 2; f->is_vararg = VARARG_ISVARARG; f->code = luaM_newvector(L, pc, Instruction); f->sizecode = pc; f->p = luaM_newvector( L, n, Proto*); f->sizep = n; for( i = pc = 0; i < n; i ++) { int proto_idx = i-n-1; Proto *p = clvalue( L->top + proto_idx)->l.p; f->p[i] = p; f->code[pc++] = CREATE_ABx( OP_CLOSURE, 0, i); f->code[pc++] = CREATE_ABx( OP_VARARG, 1, 0); f->code[pc++] = CREATE_ABC( OP_CALL, 0, 0, 1); } f->code[pc++] = CREATE_ABC( OP_RETURN, 0, 1, 0); return 1; } }
int CScriptSystem::GetFunctionParamName(HSCRIPTFUNCTION hFunc, XmlNodeRef& funcNode) { lua_getref(m_pLS, (int)hFunc); StkId func = m_pLS->top - 1; Closure* cl; if (ttype(func) != LUA_TFUNCTION) { lua_pop(m_pLS, 1); return -1; } cl = clvalue(func); int numParams = cl->l.p->numparams; int validParams = numParams; for (int j = 0, i = 0 ; j < numParams; j++) { const char* name = luaF_getlocalname(cl->l.p, j + 1, 0); BEHAVIAC_ASSERT(name); if (!string_icmp(name, "self")) { validParams--; continue; } // There is no value for now, so store the index as the value funcNode->setAttr(name, i); ++i; } lua_pop(m_pLS, 1); // lua_getref pop return validParams; }
void luaV_setglobal (lua_State *L, TString *s) { const TObject *oldvalue = luaH_getstr(L->gt, s); Closure *tm = luaT_gettmbyObj(L, oldvalue, TM_SETGLOBAL); if (tm == NULL) { /* is there a tag method? */ if (oldvalue != &luaO_nilobject) { /* cast to remove `const' is OK, because `oldvalue' != luaO_nilobject */ *(TObject *)oldvalue = *(L->top - 1); } else { TObject key; ttype(&key) = LUA_TSTRING; tsvalue(&key) = s; *luaH_set(L, L->gt, &key) = *(L->top - 1); } } else { luaD_checkstack(L, 3); *(L->top+2) = *(L->top-1); /* new value */ *(L->top+1) = *oldvalue; ttype(L->top) = LUA_TSTRING; tsvalue(L->top) = s; clvalue(L->top-1) = tm; ttype(L->top-1) = LUA_TFUNCTION; L->top += 3; luaD_call(L, L->top - 4, 0); } }
// Dump bytecode representation of function onto stack and send. This // implementation uses eLua's crosscompile dump to match match the // bytecode representation to the client/server negotiated format. static void write_function( Transport *tpt, lua_State *L, int var_index ) { TValue *o; luaL_Buffer b; DumpTargetInfo target; target.little_endian=tpt->net_little; target.sizeof_int=sizeof(int); target.sizeof_strsize_t=sizeof(strsize_t); target.sizeof_lua_Number=tpt->lnum_bytes; target.lua_Number_integral=tpt->net_intnum; target.is_arm_fpa=0; // push function onto stack, serialize to string lua_pushvalue( L, var_index ); luaL_buffinit( L, &b ); lua_lock(L); o = L->top - 1; luaU_dump_crosscompile(L,clvalue(o)->l.p,writer,&b,0,target); lua_unlock(L); // put string representation on stack and send it luaL_pushresult( &b ); write_variable( tpt, L, lua_gettop( L ) ); // Remove function & dumped string from stack lua_pop( L, 2 ); }
/* ** returns the `main' position of an element in a table (that is, the index ** of its hash value) */ Node *luaH_mainposition (const Hash *t, const TObject *key) { unsigned h; switch (ttype(key)) { case LUA_TNUMBER: h = (unsigned)(int)nvalue(key); break; case LUA_TSTRING: h = tsvalue(key)->u.s.hash; break; case LUA_TUSERDATA: h = IntPoint(tsvalue(key)); break; case LUA_TTABLE: h = IntPoint(hvalue(key)); break; case LUA_TFUNCTION: h = IntPoint(clvalue(key)); break; default: return NULL; /* invalid key */ } LUA_ASSERT(h%(unsigned int)t->size == (h&((unsigned int)t->size-1)), "a&(x-1) == a%x, for x power of 2"); return &t->node[h&(t->size-1)]; }
static int kplib_sort_pairs(ktap_state *ks) { ktap_value *v = kp_arg(ks, 1); ktap_closure *cmp_func = NULL; ktap_tab *t; if (is_table(v)) { t = hvalue(v); } else if (is_ptable(v)) { t = kp_ptab_synthesis(ks, phvalue(v)); } else if (is_nil(v)) { kp_error(ks, "table is nil in pairs\n"); return 0; } else { kp_error(ks, "wrong argument for pairs\n"); return 0; } if (kp_arg_nr(ks) > 1) { kp_arg_check(ks, 2, KTAP_TYPE_FUNCTION); cmp_func = clvalue(kp_arg(ks, 2)); } kp_tab_sort(ks, t, cmp_func); set_cfunction(ks->top++, table_sort_iter_next); set_table(ks->top++, t); set_nil(ks->top++); return 3; }
LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { int status; Closure *cl; CallInfo *ci; StkId func; lua_lock(L); if (*what == '>') { ci = NULL; func = L->top - 1; api_check(L, ttisfunction(func), "function expected"); what++; /* skip the '>' */ L->top--; /* pop function */ } else { ci = ar->i_ci; func = ci->func; lua_assert(ttisfunction(ci->func)); } cl = ttisclosure(func) ? clvalue(func) : NULL; status = auxgetinfo(L, what, ar, cl, ci); if (strchr(what, 'f')) { setobjs2s(L, L->top, func); api_incr_top(L); } if (strchr(what, 'L')) collectvalidlines(L, cl); lua_unlock(L); return status; }
/* ** Function to index a table. ** Receives the table at `t' and the key at top. */ const TObject *luaV_gettable (lua_State *L, StkId t) { Closure *tm; int tg; if (ttype(t) == LUA_TTABLE && /* `t' is a table? */ ((tg = hvalue(t)->htag) == LUA_TTABLE || /* with default tag? */ luaT_gettm(L, tg, TM_GETTABLE) == NULL)) { /* or no TM? */ /* do a primitive get */ const TObject *h = luaH_get(L, hvalue(t), L->top-1); /* result is no nil or there is no `index' tag method? */ if (ttype(h) != LUA_TNIL || ((tm=luaT_gettm(L, tg, TM_INDEX)) == NULL)) return h; /* return result */ /* else call `index' tag method */ } else { /* try a `gettable' tag method */ tm = luaT_gettmbyObj(L, t, TM_GETTABLE); } if (tm != NULL) { /* is there a tag method? */ luaD_checkstack(L, 2); *(L->top+1) = *(L->top-1); /* key */ *L->top = *t; /* table */ clvalue(L->top-1) = tm; /* tag method */ ttype(L->top-1) = LUA_TFUNCTION; L->top += 2; luaD_call(L, L->top - 3, 1); return L->top - 1; /* call result */ } else { /* no tag method */ luaG_typeerror(L, t, "index"); return NULL; /* to avoid warnings */ } }
/* local stats = jit.util.stats(func) */ static int ju_stats(lua_State *L) { if (!(L->top > L->base)) luaL_argerror(L, 1, "Lua function expected"); if (isLfunction(L->base)) { Proto *pt = clvalue(L->base)->l.p; lua_createtable(L, 0, 11); setintfield("status", pt->jit_status); setintfield("stackslots", pt->maxstacksize); setintfield("params", pt->numparams); setintfield("bytecodes", pt->sizecode); setintfield("consts", pt->sizek); setintfield("upvalues", pt->nups); setintfield("subs", pt->sizep); lua_pushboolean(L, pt->is_vararg); lua_setfield(L, -2, "isvararg"); lua_getfenv(L, 1); lua_setfield(L, -2, "env"); if (pt->jit_szmcode != 0) { setintfield("mcodesize", (int)mcodesize(pt)); lua_pushnumber(L, (lua_Number)(size_t)pt->jit_mcode); lua_setfield(L, -2, "mcodeaddr"); } return 1; } else { return 0; /* Don't throw an error like the other util functions. */ } }
int luaO_equalObj (const TObject *t1, const TObject *t2) { if (ttype(t1) != ttype(t2)) return 0; switch (ttype(t1)) { case LUA_TNUMBER: return nvalue(t1) == nvalue(t2); case LUA_TSTRING: case LUA_TUSERDATA: return tsvalue(t1) == tsvalue(t2); case LUA_TTABLE: return hvalue(t1) == hvalue(t2); case LUA_TFUNCTION: return clvalue(t1) == clvalue(t2); default: LUA_ASSERT(ttype(t1) == LUA_TNIL, "invalid type"); return 1; /* LUA_TNIL */ } }
void luaD_callTM (lua_State *L, Closure *f, int nParams, int nResults) { StkId base = L->top - nParams; luaD_openstack(L, base); clvalue(base) = f; ttype(base) = LUA_TFUNCTION; luaD_call(L, base, nResults); }
static int32 hashindex(TObject *r) { int32 h; switch (ttype(r)) { case LUA_T_NUMBER: h = (int32)nvalue(r); break; case LUA_T_USERDATA: h = (int32)r->value.ud.id; case LUA_T_STRING: h = (int32)tsvalue(r); break; case LUA_T_ARRAY: h = (int32)avalue(r); break; case LUA_T_PROTO: h = (int32)tfvalue(r); break; case LUA_T_CPROTO: h = (int32)fvalue(r); break; case LUA_T_CLOSURE: h = (int32)clvalue(r); break; case LUA_T_TASK: h = (int32)nvalue(r); break; default: lua_error("unexpected type to index table"); h = 0; // to avoid warnings } return (h >= 0 ? h : -(h + 1)); }
static long int hashindex (TObject *ref) { long int h; switch (ttype(ref)) { case LUA_T_NUMBER: h = (long int)nvalue(ref); break; case LUA_T_STRING: case LUA_T_USERDATA: h = (IntPoint)tsvalue(ref); break; case LUA_T_ARRAY: h = (IntPoint)avalue(ref); break; case LUA_T_PROTO: h = (IntPoint)tfvalue(ref); break; case LUA_T_CPROTO: h = (IntPoint)fvalue(ref); break; case LUA_T_CLOSURE: h = (IntPoint)clvalue(ref); break; default: lua_error("unexpected type to index table"); h = 0; /* to avoid warnings */ } return (h >= 0 ? h : -(h+1)); }
static void persistfunction(PersistInfo *pi) { /* perms reftbl ... func */ Closure *cl = clvalue(getobject(pi->L, -1)); lua_checkstack(pi->L, 2); if(cl->c.isC) { /* It's a C function. For now, we aren't going to allow * persistence of C closures, even if the "C proto" is * already in the permanents table. */ lua_pushstring(pi->L, "Attempt to persist a C function"); lua_error(pi->L); } else { /* It's a Lua closure. */ { /* We don't really _NEED_ the number of upvals, * but it'll simplify things a bit */ pi->writer(pi->L, &cl->l.p->nups, sizeof(lu_byte), pi->ud); } /* Persist prototype */ { pushproto(pi->L, cl->l.p); /* perms reftbl ... func proto */ persist(pi); lua_pop(pi->L, 1); /* perms reftbl ... func */ } /* Persist upvalue values (not the upvalue objects * themselves) */ { int i; for(i=0; i<cl->l.p->nups; i++) { /* perms reftbl ... func */ pushupval(pi->L, cl->l.upvals[i]); /* perms reftbl ... func upval */ persist(pi); lua_pop(pi->L, 1); /* perms reftbl ... func */ } /* perms reftbl ... func */ } /* Persist function environment */ { lua_getfenv(pi->L, -1); /* perms reftbl ... func fenv */ if(lua_equal(pi->L, -1, LUA_GLOBALSINDEX)) { /* Function has the default fenv */ /* perms reftbl ... func _G */ lua_pop(pi->L, 1); /* perms reftbl ... func */ lua_pushnil(pi->L); /* perms reftbl ... func nil */ } /* perms reftbl ... func fenv/nil */ persist(pi); lua_pop(pi->L, 1); /* perms reftbl ... func */ } } }
int debug_getsize(lua_State* L) { TValue* o = L->base; switch (o->tt) { /* Container types */ case LUA_TTABLE: { Table *h = hvalue(o); lua_pushinteger(L, sizeof(Table) + sizeof(TValue) * h->sizearray + sizeof(Node) * sizenode(h)); break; } case LUA_TFUNCTION: { Closure *cl = clvalue(o); lua_pushinteger(L, (cl->c.isC) ? sizeCclosure(cl->c.nupvalues) : sizeLclosure(cl->l.nupvalues)); break; } case LUA_TTHREAD: { lua_State *th = thvalue(o); lua_pushinteger(L, sizeof(lua_State) + sizeof(TValue) * th->stacksize + sizeof(CallInfo) * th->size_ci); break; } case LUA_TPROTO: { Proto *p = pvalue(o); lua_pushinteger(L, sizeof(Proto) + sizeof(Instruction) * p->sizecode + sizeof(Proto *) * p->sizep + sizeof(TValue) * p->sizek + sizeof(int) * p->sizelineinfo + sizeof(LocVar) * p->sizelocvars + sizeof(TString *) * p->sizeupvalues); break; } /* Non-containers */ case LUA_TUSERDATA: { lua_pushnumber(L, uvalue(o)->len); break; } case LUA_TLIGHTUSERDATA: { lua_pushnumber(L, sizeof(void*)); break; } case LUA_TSTRING: { TString *s = rawtsvalue(o); lua_pushinteger(L, sizeof(TString) + s->tsv.len + 1); break; } case LUA_TNUMBER: { lua_pushinteger(L, sizeof(lua_Number)); break; } case LUA_TBOOLEAN: { lua_pushinteger(L, sizeof(int)); break; } default: return 0; } return 1; }
LUA_API void lua_getfenv (lua_State *L, int idx) { StkId o; lua_lock(L); o = luaA_index(L, idx); setobj2s(L->top, isLfunction(o) ? &clvalue(o)->l.g : gt(L)); api_incr_top(L); lua_unlock(L); }
void boxUpValue_finish(lua_State *luaState) { // >>>>> ...... func obj LClosure *lcl = (LClosure *)clvalue(getObject(luaState, -2)); lcl->upvals[0]->u.value = *getObject(luaState, -1); lua_pop(luaState, 1); // >>>>> ...... func }
/* weet: * 1. 用负值索引找栈中的对象 * 2. 可以看出一些栈的设计思路 * */ static TObject *negindex (lua_State *L, int idx) { if (idx > LUA_REGISTRYINDEX) { api_check(L, idx != 0 && -idx <= L->top - L->base); return L->top+idx; } else switch (idx) { /* pseudo-indices */ case LUA_REGISTRYINDEX: return registry(L); case LUA_GLOBALSINDEX: return gt(L); default: { TObject *func = (L->base - 1); idx = LUA_GLOBALSINDEX - idx; lua_assert(iscfunction(func)); return (idx <= clvalue(func)->c.nupvalues) /* (weet: 哈哈, 原来lua把闭包变量放在这个地方!! */ ? &clvalue(func)->c.upvalue[idx-1] : NULL; } } }
static Closure *luaV_closure (lua_State *L, int nelems) { Closure *c = luaF_newclosure(L, nelems); L->top -= nelems; while (nelems--) c->upvalue[nelems] = *(L->top+nelems); clvalue(L->top) = c; ttype(L->top) = LUA_TFUNCTION; incr_top; return c; }
/* ** Call a function (C or Lua). The function to be called is at *func. ** The arguments are on the stack, right after the function. ** When returns, the results are on the stack, starting at the original ** function position. ** The number of results is nResults, unless nResults=LUA_MULTRET. */ void luaD_call (lua_State *L, StkId func, int nResults) { lua_Hook callhook; StkId firstResult; CallInfo ci; Closure *cl; if (ttype(func) != LUA_TFUNCTION) { /* `func' is not a function; check the `function' tag method */ Closure *tm = luaT_gettmbyObj(L, func, TM_FUNCTION); if (tm == NULL) luaG_typeerror(L, func, "call"); luaD_openstack(L, func); clvalue(func) = tm; /* tag method is the new function to be called */ ttype(func) = LUA_TFUNCTION; } cl = clvalue(func); ci.func = cl; infovalue(func) = &ci; ttype(func) = LUA_TMARK; callhook = L->callhook; if (callhook) luaD_callHook(L, func, callhook, "call"); firstResult = (cl->isC ? callCclosure(L, cl, func+1) : luaV_execute(L, cl, func+1)); if (callhook) /* same hook that was active at entry */ luaD_callHook(L, func, callhook, "return"); LUA_ASSERT(ttype(func) == LUA_TMARK, "invalid tag"); /* move results to `func' (to erase parameters and function) */ if (nResults == LUA_MULTRET) { while (firstResult < L->top) /* copy all results */ *func++ = *firstResult++; L->top = func; } else { /* copy at most `nResults' */ for (; nResults > 0 && firstResult < L->top; nResults--) *func++ = *firstResult++; L->top = func; for (; nResults > 0; nResults--) { /* if there are not enough results */ ttype(L->top) = LUA_TNIL; /* adjust the stack */ incr_top; /* must check stack space */ } } luaC_checkGC(L); }
static int nups (StkId f) { switch (ttype(f)) { case LUA_TFUNCTION: return clvalue(f)->nupvalues; case LUA_TMARK: return infovalue(f)->func->nupvalues; default: return 0; } }
LUA_API const void *lua_topointer (lua_State *L, int index) { StkId o = luaA_indexAcceptable(L, index); if (o == NULL) return NULL; switch (ttype(o)) { case LUA_TTABLE: return hvalue(o); case LUA_TFUNCTION: return clvalue(o); default: return NULL; } }
static void unboxupval(lua_State *L) { /* ... func */ LClosure *lcl; UpVal *uv; lcl = (LClosure*)clvalue(getobject(L, -1)); uv = lcl->upvals[0]; lua_pop(L, 1); /* ... */ pushupval(L, uv); /* ... upval */ }
static const char *travtagmethods (lua_State *L, const TObject *o) { if (ttype(o) == LUA_TFUNCTION) { int e; for (e=0; e<TM_N; e++) { int t; for (t=0; t<=L->last_tag; t++) if (clvalue(o) == luaT_gettm(L, t, e)) return luaT_eventname[e]; } } return NULL; }
TObject *negindex (lua_State *L, int idx) { if (idx > LUA_REGISTRYINDEX) { api_check(L, idx != 0 && -idx <= L->top - L->base); return L->top+idx; } else if (idx < -40000) { return (TObject*)luaH_getnum(hvalue(registry(L)), -idx - 40000); } else switch (idx) { /* pseudo-indices */ case LUA_REGISTRYINDEX: return registry(L); case LUA_GLOBALSINDEX: return gt(L); default: { TObject *func = (L->base - 1); idx = LUA_GLOBALSINDEX - idx; lua_assert(iscfunction(func)); return (idx <= clvalue(func)->c.nupvalues) ? &clvalue(func)->c.upvalue[idx-1] : NULL; } } }
static int hasmark (const TObject *o) { /* valid only for locked objects */ switch (o->ttype) { case LUA_TSTRING: case LUA_TUSERDATA: return tsvalue(o)->marked; case LUA_TTABLE: return ismarked(hvalue(o)); case LUA_TFUNCTION: return ismarked(clvalue(o)); default: /* number */ return 1; } }