static int call_binTM (lua_State *L, const TObject *p1, const TObject *p2, StkId res, TMS event) { ptrdiff_t result = savestack(L, res); const TObject *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ if (ttisnil(tm)) tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ if (!ttisfunction(tm)) return 0; callTMres(L, tm, p1, p2); res = restorestack(L, result); /* previous call may change stack */ setobjs2s(res, L->top); return 1; }
void luaG_errormsg (lua_State *L) { if (L->errfunc != 0) { /* is there an error handling function? */ StkId errfunc = restorestack(L, L->errfunc); if (!ttisfunction(errfunc) && !ttislightfunction(errfunc)) luaD_throw(L, LUA_ERRERR); setobjs2s(L, L->top, L->top - 1); /* move argument */ setobjs2s(L, L->top - 1, errfunc); /* push function */ incr_top(L); luaD_call(L, L->top - 2, 1); /* call it */ } luaD_throw(L, LUA_ERRRUN); }
LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { int status = 1; lua_lock(L); if (*what == '>') { StkId f = L->top - 1; if (!ttisfunction(f)) luaG_runerror(L, "value for `lua_getinfo' is not a function"); status = auxgetinfo(L, what + 1, ar, f, NULL); L->top--; /* pop function */ } else if (ar->i_ci != 0) { /* no tail call? */ CallInfo *ci = L->base_ci + ar->i_ci; lua_assert(ttisfunction(ci->base - 1)); status = auxgetinfo(L, what, ar, ci->base - 1, ci); } else info_tailcall(L, ar); if (strchr(what, 'f')) incr_top(L); lua_unlock(L); return status; }
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; }
void luaG_errormsg (lua_State *L) { if (L->errfunc != 0) { /* is there an error handling function? */ StkId errfunc = restorestack(L, L->errfunc); if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR); setobjs2s(L, L->top, L->top - 1); /* move argument */ setobjs2s(L, L->top - 1, errfunc); /* push function */ incr_top(L); luaD_call(L, L->top - 2, 1); /* call it */ }else if (L->def_errfunc && lua_checkstack(L, LUA_MINSTACK)) { L->def_errfunc(L); // dunno about locks etc. } luaD_throw(L, LUA_ERRRUN); }
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; }
void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { TValue tmp; int loop; for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; if (ttistable(t)) { /* `t' is a table? */ Table *h = hvalue(t); TValue *oldval = luaH_set(L, h, key); /* do a primitive set */ if (!ttisnil(oldval) || /* result is no nil? */ (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ setobj2t(L, oldval, val); luaC_barriert(L, h, val); #if LUA_REFCOUNT if (ttisnil(val)) { Node* keyNode = luaH_getkey(h, key); if (keyNode) { luaH_removekey(L, h, keyNode); } } #endif /* LUA_REFCOUNT */ return; } /* else will try the tag method */ } else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) luaG_typeerror(L, t, "index"); if (ttisfunction(tm)) { callTM(L, tm, t, key, val); #if LUA_REFCOUNT { TValue *newval; if (ttistable(t)) { newval = luaH_set(L, hvalue(t), key); if (ttisnil(newval)) { Node* keyNode = luaH_getkey(hvalue(t), key); if (keyNode) luaH_removekey(L, hvalue(t), keyNode); } } } #endif /* LUA_REFCOUNT */ return; } setobj(L, &tmp, tm); t = &tmp; /* else repeat with copy of `tm' */ } luaG_runerror(L, "loop in settable"); }
/* ** Main function for table assignment (invoking metamethods if needed). ** Compute 't[key] = val' */ void luaV_finishset (lua_State *L, const TValue *t, TValue *key, StkId val, const TValue *oldval) { int loop; /* counter to avoid infinite loops */ for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; if (oldval != NULL) { Table *h = hvalue(t); /* save 't' table */ lua_assert(ttisnil(oldval)); /* must check the metamethod */ if ((tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL && /* no metamethod; is there a previous entry in the table? */ (oldval != luaO_nilobject || /* no previous entry; must create one. (The next test is always true; we only need the assignment.) */ (oldval = luaH_newkey(L, h, key), 1))) { /* no metamethod and (now) there is an entry with given key */ setobj2t(L, cast(TValue *, oldval), val); invalidateTMcache(h); luaC_barrierback(L, h, val); return; } /* else will try the metamethod */ } else { /* not a table; check metamethod */ if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) luaG_typeerror(L, t, "index"); } /* try the metamethod */ if (ttisfunction(tm)) { luaT_callTM(L, tm, t, key, val, 0); return; } t = tm; /* else repeat assignment over 'tm' */ if (luaV_fastset(L, t, key, oldval, luaH_get, val)) return; /* done */ /* else loop */ } luaG_runerror(L, "settable chain too long; possible loop"); }
void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { int loop; TValue temp; setnilvalue(L->top); L->top++; fixedstack(L); for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; if (ttistable(t) || ttisrotable(t)) { /* `t' is a table? */ void *h = ttistable(t) ? hvalue(t) : rvalue(t); TValue *oldval = ttistable(t) ? luaH_set(L, (Table*)h, key) : NULL; /* do a primitive set */ if ((oldval && !ttisnil(oldval)) || /* result is no nil? */ (tm = fasttm(L, ttistable(t) ? ((Table*)h)->metatable : (Table*)luaR_getmeta(h), TM_NEWINDEX)) == NULL) { /* or no TM? */ if(oldval) { L->top--; unfixedstack(L); setobj2t(L, oldval, val); ((Table *)h)->flags = 0; luaC_barriert(L, (Table*)h, val); } return; } /* else will try the tag method */ } else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) luaG_typeerror(L, t, "index"); if (ttisfunction(tm) || ttislightfunction(tm)) { L->top--; unfixedstack(L); callTM(L, tm, t, key, val); return; } /* else repeat with `tm' */ setobj(L, &temp, tm); /* avoid pointing inside table (may rehash) */ t = &temp; setobj2s(L, L->top-1, t); /* need to protect value from EGC. */ } luaG_runerror(L, "loop in settable"); }
/* ** Complete a table access: if 't' is a table, 'tm' has its metamethod; ** otherwise, 'tm' is NULL. */ void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, const TValue *tm) { int loop; /* counter to avoid infinite loops */ lua_assert(tm != NULL || !ttistable(t)); for (loop = 0; loop < MAXTAGLOOP; loop++) { if (tm == NULL) { /* no metamethod (from a table)? */ if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) luaG_typeerror(L, t, "index"); /* no metamethod */ } if (ttisfunction(tm)) { /* metamethod is a function */ luaT_callTM(L, tm, t, key, val, 1); /* call it */ return; } t = tm; /* else repeat access over 'tm' */ if (luaV_fastget(L,t,key,tm,luaH_get)) { /* try fast track */ setobj2s(L, val, tm); /* done */ return; } /* else repeat */ } luaG_runerror(L, "gettable chain too long; possible loop"); }
void luaG_errormsg (lua_State *L) { if (L->errfunc != 0) { /* is there an error handling function? */ StkId errfunc = restorestack(L, L->errfunc); if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR); setobjs2s(L, L->top, L->top - 1); /* move argument */ setobjs2s(L, L->top - 1, errfunc); /* push function */ incr_top(L); luaD_call(L, L->top - 2, 1); /* call it */ } else { lua_getfield(L, LUA_GLOBALSINDEX, "_ErrorHandler"); if (!lua_isfunction(L, -1)) { lua_pop(L, 1); } else { lua_pushvalue(L, 1); lua_call(L, 1, 1); lua_pop(L, 1); } } luaD_throw(L, LUA_ERRRUN); }
/* ** Main function for table assignment (invoking metamethods if needed). ** Compute 't[key] = val' */ void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { int loop; /* counter to avoid infinite loops */ for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; if (ttistable(t)) { /* 't' is a table? */ Table *h = hvalue(t); TValue *oldval = cast(TValue *, luaH_get(h, key)); /* if previous value is not nil, there must be a previous entry in the table; a metamethod has no relevance */ tm = ttisnil(oldval) ? fasttm(L, h->metatable, TM_NEWINDEX) : fasttm(L, h->metatable, TM_OLDINDEX); if (tm == NULL && (oldval != luaO_nilobject || /* no previous entry; must create one. (The next test is always true; we only need the assignment.) */ (oldval = luaH_newkey(L, h, key), 1))) { /* no metamethod and (now) there is an entry with given key */ setobj2t(L, oldval, val); /* assign new value to that entry */ invalidateTMcache(h); luaC_barrierback(L, h, val); return; } /* else will try the metamethod */ } else { /* not a table; check metamethod */ if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) luaG_typeerror(L, t, "index"); if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_OLDINDEX))) luaG_typeerror(L, t, "index"); } /* try the metamethod */ if (ttisfunction(tm)) { luaT_callTM(L, tm, t, key, val, 0); return; } t = tm; /* else repeat assignment over 'tm' */ }
void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { int loop; for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; if (ttistable(t)) { /* `t' is a table? */ Table *h = hvalue(t); const TValue *res = luaH_get(h, key); /* do a primitive get */ if (!ttisnil(res) || /* result is no nil? */ (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */ setobj2s(L, val, res); return; } /* else will try the tag method */ } else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) luaG_typeerror(L, t, "index"); if (ttisfunction(tm)) { callTMres(L, val, tm, t, key); return; } t = tm; /* else repeat with `tm' */ } luaG_runerror(L, "loop in gettable"); }
/* ** Main function for table access (invoking metamethods if needed). ** Compute 'val = t[key]' */ void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { int loop; /* counter to avoid infinite loops */ for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; if (ttistable(t)) { /* 't' is a table? */ Table *h = hvalue(t); const TValue *res = luaH_get(h, key); /* do a primitive get */ if (!ttisnil(res) || /* result is not nil? */ (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */ setobj2s(L, val, res); /* result is the raw get */ return; } /* else will try metamethod */ } else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) luaG_typeerror(L, t, "index"); /* no metamethod */ if (ttisfunction(tm)) { /* metamethod is a function */ luaT_callTM(L, tm, t, key, val, 1); return; } t = tm; /* else repeat access over 'tm' */ } luaG_runerror(L, "gettable chain too long; possible loop"); }
/* ** Finish a table assignment 't[key] = val'. ** If 'slot' is NULL, 't' is not a table. Otherwise, 'slot' points ** to the entry 't[key]', or to 'luaO_nilobject' if there is no such ** entry. (The value at 'slot' must be nil, otherwise 'luaV_fastset' ** would have done the job.) */ void luaV_finishset (lua_State *L, const TValue *t, TValue *key, StkId val, const TValue *slot) { int loop; /* counter to avoid infinite loops */ for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; /* '__newindex' metamethod */ if (slot != NULL) { /* is 't' a table? */ Table *h = hvalue(t); /* save 't' table */ lua_assert(ttisnil(slot)); /* old value must be nil */ tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */ if (tm == NULL) { /* no metamethod? */ if (slot == luaO_nilobject) /* no previous entry? */ slot = luaH_newkey(L, h, key); /* create one */ /* no metamethod and (now) there is an entry with given key */ setobj2t(L, cast(TValue *, slot), val); /* set its new value */ invalidateTMcache(h); luaC_barrierback(L, h, val); return; } /* else will try the metamethod */ } else { /* not a table; check metamethod */ if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) luaG_typeerror(L, t, "index"); } /* try the metamethod */ if (ttisfunction(tm)) { luaT_callTM(L, tm, t, key, val, 0); return; } t = tm; /* else repeat assignment over 'tm' */ if (luaV_fastset(L, t, key, slot, luaH_get, val)) return; /* done */ /* else loop */ } luaG_runerror(L, "'__newindex' chain too long; possible loop"); }
/* ** Receives table at `t', key at `key' and value at `val'. */ void luaV_settable (lua_State *L, const TObject *t, TObject *key, StkId val) { const TObject *tm; int loop = 0; do { if (ttistable(t)) { /* `t' is a table? */ Table *h = hvalue(t); TObject *oldval = luaH_set(L, h, key); /* do a primitive set */ if (!ttisnil(oldval) || /* result is no nil? */ (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ setobj2t(oldval, val); /* write barrier */ return; } /* else will try the tag method */ } else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) luaG_typeerror(L, t, "index"); if (ttisfunction(tm)) { callTM(L, tm, t, key, val); return; } t = tm; /* else repeat with `tm' */ } while (++loop <= MAXTAGLOOP); luaG_runerror(L, "loop in settable"); }
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 luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { int loop; for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm = 0; /* LUA-VEC -- compiler gives a warning of uninitialized value on this so we set it to 0 */ if (ttistable(t)) { /* `t' is a table? */ Table *h = hvalue(t); const TValue *res = luaH_get(h, key); /* do a primitive get */ if (!ttisnil(res) || /* result is no nil? */ (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */ setobj2s(L, val, res); return; } /* else will try the tag method */ } else if (ttisvec(t)) { /* LUA-VEC -- vec[idx] operator */ /* issue: "index" may not be the correct arg for luaG_typeerror in here */ if (ttisnumber(key) && /* acessing vec by a number? */ (nvalue(key) >= 1 && nvalue(key) <= 4)) { /* index is between 1-4? */ TValue res; setnvalue(&res, vecvalue(t)[(int)nvalue(key)-1]); setobj2s(L, val, &res); return; } else if (ttisstring(key)) { /* acessing vec by a string? */ if (tsvalue(key)->len == 1) { /* accessing by a single component, such as vec.x */ TValue res; switch (*getstr(tsvalue(key))) { case 'x': setnvalue(&res, vecvalue(t)[0]); break; case 'y': setnvalue(&res, vecvalue(t)[1]); break; case 'z': setnvalue(&res, vecvalue(t)[2]); break; case 'w': setnvalue(&res, vecvalue(t)[3]); break; default: luaG_typeerror(L, t, "index"); } setobj2s(L, val, &res); return; } else if (tsvalue(key)->len <= 4) { /* accessing by swizzling, such as vec.xy, vec.xxyz etc. */ TValue res; float v[4] = {0.0f,0.0f,0.0f,0.0f}; int i; for (i = 0; i < (int)tsvalue(key)->len; ++i) { switch (getstr(tsvalue(key))[i]) { case 'x': v[i] = vecvalue(t)[0]; break; case 'y': v[i] = vecvalue(t)[1]; break; case 'z': v[i] = vecvalue(t)[2]; break; case 'w': v[i] = vecvalue(t)[3]; break; default: luaG_typeerror(L, t, "index"); } } setvecvalue(&res, v[0], v[1], v[2], v[3]); setobj2s(L, val, &res); return; } } luaG_typeerror(L, t, "index"); } else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) luaG_typeerror(L, t, "index"); if (ttisfunction(tm)) { callTMres(L, val, tm, t, key); return; } t = tm; /* else repeat with `tm' */ } luaG_runerror(L, "loop in gettable"); }