l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) { CallInfo *ci = L->ci; const char *name = NULL; const char *t = objtypename(o); const char *kind = NULL; if (isLua(ci)) { kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */ if (!kind && isinstack(ci, o)) /* no? try a register */ kind = getobjname(ci_func(ci)->p, currentpc(ci), cast_int(o - ci->u.l.base), &name); } if (kind) luaG_runerror(L, "attempt to %s %s " LUA_QS " (a %s value)", op, kind, name, t); else luaG_runerror(L, "attempt to %s a %s value", op, t); }
static const char *getobjname (lua_State *L, CallInfo *ci, int stackpos, const char **name) { if (isLua(ci)) { /* a Lua function? */ Proto *p = ci_func(ci)->l.p; int pc = currentpc(L, ci); Instruction i; *name = luaF_getlocalname(p, stackpos+1, pc); if (*name) /* is a local? */ return "local"; i = symbexec(p, pc, stackpos); /* try symbolic execution */ lua_assert(pc != -1); switch (GET_OPCODE(i)) { case OP_GETGLOBAL: { int g = GETARG_Bx(i); /* global index */ lua_assert(ttisstring(&p->k[g])); *name = svalue(&p->k[g]); return "global"; } case OP_MOVE: { int a = GETARG_A(i); int b = GETARG_B(i); /* move from `b' to `a' */ if (b < a) return getobjname(L, ci, b, name); /* get name for `b' */ break; } case OP_GETTABLE: { int k = GETARG_C(i); /* key index */ *name = kname(p, k); return "field"; } case OP_GETUPVAL: { int u = GETARG_B(i); /* upvalue index */ *name = p->upvalues ? getstr(p->upvalues[u]) : "?"; return "upvalue"; } case OP_SELF: { int k = GETARG_C(i); /* key index */ *name = kname(p, k); return "method"; } default: break; } } return NULL; /* no useful name found */ }
/* ** Try to find a name for a function based on the code that called it. ** (Only works when function was called by a Lua function.) ** Returns what the name is (e.g., "for iterator", "method", ** "metamethod") and sets '*name' to point to the name. */ static const char *funcnamefromcode (lua_State *L, CallInfo *ci, const char **name) { TMS tm = (TMS)0; /* (initial value avoids warnings) */ Proto *p = ci_func(ci)->p; /* calling function */ int pc = currentpc(ci); /* calling instruction index */ Instruction i = p->code[pc]; /* calling instruction */ if (ci->callstatus & CIST_HOOKED) { /* was it called inside a hook? */ *name = "?"; return "hook"; } switch (GET_OPCODE(i)) { case OP_CALL: case OP_TAILCALL: return getobjname(p, pc, GETARG_A(i), name); /* get function name */ case OP_TFORCALL: { /* for iterator */ *name = "for iterator"; return "for iterator"; } /* other instructions can do calls through metamethods */ case OP_SELF: case OP_GETTABUP: case OP_GETTABLE: tm = TM_INDEX; break; case OP_SETTABUP: case OP_SETTABLE: tm = TM_NEWINDEX; break; case OP_ADD: case OP_SUB: case OP_MUL: case OP_MOD: case OP_POW: case OP_DIV: case OP_IDIV: case OP_BAND: case OP_BOR: case OP_BXOR: case OP_SHL: case OP_SHR: { int offset = cast_int(GET_OPCODE(i)) - cast_int(OP_ADD); /* ORDER OP */ tm = cast(TMS, offset + cast_int(TM_ADD)); /* ORDER TM */ break; } case OP_UNM: tm = TM_UNM; break; case OP_BNOT: tm = TM_BNOT; break; case OP_LEN: tm = TM_LEN; break; case OP_CONCAT: tm = TM_CONCAT; break; case OP_EQ: tm = TM_EQ; break; case OP_LT: tm = TM_LT; break; case OP_LE: tm = TM_LE; break; default: return NULL; /* cannot find a reasonable name */ } *name = getstr(G(L)->tmname[tm]); return "metamethod"; }
static void traceexec (lua_State *L, const Instruction *pc) { lu_byte mask = L->hookmask; const Instruction *oldpc = L->savedpc; L->savedpc = pc; if ((mask & LUA_MASKCOUNT) && L->hookcount == 0) { resethookcount(L); luaD_callhook(L, LUA_HOOKCOUNT, -1); } if (mask & LUA_MASKLINE) { Proto *p = ci_func(L->ci)->l.p; int npc = pcRel(pc, p); int newline = getline(p, npc); /* call linehook when enter a new function, when jump back (loop), or when enter a new line */ if (npc == 0 || pc <= oldpc || newline != getline(p, pcRel(oldpc, p))) luaD_callhook(L, LUA_HOOKLINE, newline); } }
/* 内部栈跟踪 * L 虚拟机状态 */ static void traceexec (lua_State *L) { CallInfo *ci = L->ci; /* 获取调用链表 */ lu_byte mask = L->hookmask; /* hook掩码 */ /* 如果hook计数等于0,则重新获取hook的数量 */ int counthook = ((mask & LUA_MASKCOUNT) && L->hookcount == 0); /* 如果计数不为空,则重新设置 */ if (counthook) resethookcount(L); /* reset count */ /* 最后一次调用hook函数 */ if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */ /* 取消hook调用掩码 */ ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */ return; /* do not call hook again (VM yielded, so it did not move) */ } /* 如果hook计数不为空,则调用hook函数 */ if (counthook) luaD_hook(L, LUA_HOOKCOUNT, -1); /* call count hook */ /* 行hook */ if (mask & LUA_MASKLINE) { Proto *p = ci_func(ci)->p; int npc = pcRel(ci->u.l.savedpc, p); int newline = getfuncline(p, npc); if (npc == 0 || /* call linehook when enter a new function, */ ci->u.l.savedpc <= L->oldpc || /* when jump back (loop), or when */ newline != getfuncline(p, pcRel(L->oldpc, p))) /* enter a new line */ luaD_hook(L, LUA_HOOKLINE, newline); /* call line hook */ } /* 保存要返回的pc寄存器的值 */ L->oldpc = ci->u.l.savedpc; /* 如果虚拟机的状态是挂起 */ if (L->status == LUA_YIELD) { /* did hook yield? */ if (counthook) L->hookcount = 1; /* undo decrement to zero */ ci->u.l.savedpc--; /* undo increment (resume will increment it again) */ ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */ ci->func = L->top - 1; /* protect stack below results */ luaD_throw(L, LUA_YIELD); } }
// [@lvm] 检查并调用hook函数 static void traceexec (lua_State *L, const Instruction *pc) { lu_byte mask = L->hookmask; const Instruction *oldpc = L->savedpc; L->savedpc = pc; if (mask > LUA_MASKLINE) { /* instruction-hook set? */ if (L->hookcount == 0) { resethookcount(L); luaD_callhook(L, LUA_HOOKCOUNT, -1); } } if (mask & LUA_MASKLINE) { Proto *p = ci_func(L->ci)->l.p; int npc = pcRel(pc, p); //now pc int newline = getline(p, npc); /* call linehook when enter a new function, when jump back (loop), or when enter a new line */ // 看仔细了:`when jump back`,对应pc <= oldpc。这也算newline,所以导致 // LDT会在同一行停呀停! if (npc == 0 || pc <= oldpc || newline != getline(p, pcRel(oldpc, p))) luaD_callhook(L, LUA_HOOKLINE, newline); } }
static void traceexec (lua_State *L) { CallInfo *ci = L->ci; lu_byte mask = L->hookmask; if ((mask & LUA_MASKCOUNT) && L->hookcount == 0) { resethookcount(L); luaD_hook(L, LUA_HOOKCOUNT, -1); } if (mask & LUA_MASKLINE) { Proto *p = ci_func(ci)->p; int npc = pcRel(ci->u.l.savedpc, p); int newline = getfuncline(p, npc); if (npc == 0 || /* call linehook when enter a new function, */ ci->u.l.savedpc <= L->oldpc || /* when jump back (loop), or when */ newline != getfuncline(p, pcRel(L->oldpc, p))) /* enter a new line */ luaD_hook(L, LUA_HOOKLINE, newline); } L->oldpc = ci->u.l.savedpc; if (L->status == LUA_YIELD) { /* did hook yield? */ ci->u.l.savedpc--; /* undo increment (resume will increment it again) */ luaD_throw(L, LUA_YIELD); } }
static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { TMS tm; Proto *p = ci_func(ci)->p; /* calling function */ int pc = currentpc(ci); /* calling instruction index */ Instruction i = p->code[pc]; /* calling instruction */ switch (GET_OPCODE(i)) { case OP_CALL: case OP_TAILCALL: /* get function name */ return getobjname(p, pc, GETARG_A(i), name); case OP_TFORCALL: { /* for iterator */ *name = "for iterator"; return "for iterator"; } /* all other instructions can call only through metamethods */ case OP_SELF: case OP_GETTABUP: case OP_GETTABLE: tm = TM_INDEX; break; case OP_SETTABUP: case OP_SETTABLE: tm = TM_NEWINDEX; break; case OP_EQ: tm = TM_EQ; break; case OP_ADD: tm = TM_ADD; break; case OP_SUB: tm = TM_SUB; break; case OP_MUL: tm = TM_MUL; break; case OP_DIV: tm = TM_DIV; break; case OP_IDIV: tm = TM_IDIV; break; case OP_MOD: tm = TM_MOD; break; case OP_POW: tm = TM_POW; break; case OP_UNM: tm = TM_UNM; break; case OP_LEN: tm = TM_LEN; break; case OP_LT: tm = TM_LT; break; case OP_LE: tm = TM_LE; break; case OP_CONCAT: tm = TM_CONCAT; break; default: return NULL; /* else no useful name can be found */ } *name = getstr(G(L)->tmname[tm]); return "metamethod"; }
static const char *findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) { const char *name = NULL; StkId base; if (isLua(ci)) { if (n < 0) /* access to vararg values? */ return findvararg(ci, -n, pos); else { base = ci->u.l.base; name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci)); } } else base = ci->func + 1; if (name == NULL) { /* no 'standard' name? */ StkId limit = (ci == L->ci) ? L->top : ci->next->func; if (limit - base >= n && n > 0) /* is 'n' inside 'ci' stack? */ name = "(*temporary)"; /* generic name for any valid slot */ else return NULL; /* no name */ } *pos = base + (n - 1); return name; }
static int currentline (CallInfo *ci) { return getfuncline(ci_func(ci)->p, currentpc(ci)); }
static int currentpc (CallInfo *ci) { lua_assert(isLua(ci)); return pcRel(ci->u.l.savedpc, ci_func(ci)->p); }
static Proto* getluaproto(CallInfo* ci) { return (isLua(ci) ? ci_func(ci)->l.p : NULL); }
static int currentpc (lua_State *L, CallInfo *ci) { if (!isLua(ci)) return -1; /* function is not a Lua function? */ if (ci == L->ci) ci->savedpc = L->savedpc; return pcRel(ci->savedpc, ci_func(ci)->l.p); }
/* Persist all stack members */ static void persistthread(PersistInfo *pi) { size_t posremaining; lua_State *L2; /* perms reftbl ... thr */ L2 = lua_tothread(pi->L, -1); lua_checkstack(pi->L, L2->top - L2->stack + 1); if(pi->L == L2) { lua_pushstring(pi->L, "Can't persist currently running thread"); lua_error(pi->L); return; /* not reached */ } /* Persist the stack */ posremaining = revappendstack(L2, pi->L); /* perms reftbl ... thr (rev'ed contents of L2) */ pi->writer(pi->L, &posremaining, sizeof(size_t), pi->ud); for(; posremaining > 0; posremaining--) { persist(pi); lua_pop(pi->L, 1); } /* perms reftbl ... thr */ /* Now, persist the CallInfo stack. */ { size_t i, numframes = (L2->ci - L2->base_ci) + 1; pi->writer(pi->L, &numframes, sizeof(size_t), pi->ud); for(i=0; i<numframes; i++) { CallInfo *ci = L2->base_ci + i; size_t stackbase = ci->base - L2->stack; size_t stackfunc = ci->func - L2->stack; size_t stacktop = ci->top - L2->stack; size_t savedpc = (ci != L2->base_ci) ? ci->savedpc - ci_func(ci)->l.p->code : 0; pi->writer(pi->L, &stackbase, sizeof(size_t), pi->ud); pi->writer(pi->L, &stackfunc, sizeof(size_t), pi->ud); pi->writer(pi->L, &stacktop, sizeof(size_t), pi->ud); pi->writer(pi->L, &ci->nresults, sizeof(int), pi->ud); pi->writer(pi->L, &savedpc, sizeof(size_t), pi->ud); } } /* Serialize the state's other parameters, with the exception of upval stuff */ { size_t stackbase = L2->base - L2->stack; size_t stacktop = L2->top - L2->stack; lua_assert(L2->nCcalls <= 1); pi->writer(pi->L, &L2->status, sizeof(lu_byte), pi->ud); pi->writer(pi->L, &stackbase, sizeof(size_t), pi->ud); pi->writer(pi->L, &stacktop, sizeof(size_t), pi->ud); pi->writer(pi->L, &L2->errfunc, sizeof(ptrdiff_t), pi->ud); } /* Finally, record upvalues which need to be reopened */ /* See the comment above persistupval() for why we do this */ { GCObject *gco; UpVal *uv; /* perms reftbl ... thr */ for(gco = L2->openupval; gco != NULL; gco = uv->next) { size_t stackpos; uv = gco2uv(gco); /* Make sure upvalue is really open */ lua_assert(uv->v != &uv->u.value); pushupval(pi->L, uv); /* perms reftbl ... thr uv */ persist(pi); lua_pop(pi->L, 1); /* perms reftbl ... thr */ stackpos = uv->v - L2->stack; pi->writer(pi->L, &stackpos, sizeof(size_t), pi->ud); } /* perms reftbl ... thr */ lua_pushnil(pi->L); /* perms reftbl ... thr nil */ persist(pi); lua_pop(pi->L, 1); /* perms reftbl ... thr */ } /* perms reftbl ... thr */ }
static Proto *ICACHE_FLASH_ATTR getluaproto (CallInfo *ci) { return (isLua(ci) ? ci_func(ci)->l.p : NULL); }
/* Persist all stack members */ static void persistthread(PersistInfo *pi) { int posremaining; lua_State *L2; /* perms reftbl ... thr */ L2 = lua_tothread(pi->L, -1); if(pi->L == L2) { lua_pushstring(pi->L, "Can't persist currently running thread"); lua_error(pi->L); return; /* not reached */ } posremaining = revappendstack(L2, pi->L); /* perms reftbl ... thr (rev'ed contents of L2) */ pi->writer(pi->L, &posremaining, sizeof(int), pi->ud); for(; posremaining > 0; posremaining--) { persist(pi); lua_pop(pi->L, 1); } /* perms reftbl ... thr */ /* Now, persist the CallInfo stack. */ { int i, numframes = (L2->ci - L2->base_ci) + 1; pi->writer(pi->L, &numframes, sizeof(int), pi->ud); for(i=0; i<numframes; i++) { CallInfo *ci = L2->base_ci + i; int stackbase = ci->base - L2->stack; int stacktop = ci->top - L2->stack; int pc = (ci != L2->base_ci) ? ci->u.l.savedpc - ci_func(ci)->l.p->code : 0; pi->writer(pi->L, &stackbase, sizeof(int), pi->ud); pi->writer(pi->L, &stacktop, sizeof(int), pi->ud); pi->writer(pi->L, &pc, sizeof(int), pi->ud); pi->writer(pi->L, &(ci->state), sizeof(int), pi->ud); } } /* Serialize the state's top and base */ { int stackbase = L2->base - L2->stack; int stacktop = L2->top - L2->stack; pi->writer(pi->L, &stackbase, sizeof(int), pi->ud); pi->writer(pi->L, &stacktop, sizeof(int), pi->ud); } /* Finally, record upvalues which need to be reopened */ /* See the comment above persistupval() for why we do this */ { UpVal *uv; /* perms reftbl ... thr */ for(uv = gcotouv(L2->openupval); uv != NULL; uv = gcotouv(uv->next)) { int stackpos; /* Make sure upvalue is really open */ lua_assert(uv->v != &uv->value); pushupval(pi->L, uv); /* perms reftbl ... thr uv */ persist(pi); lua_pop(pi->L, 1); /* perms reftbl ... thr */ stackpos = uv->v - L2->stack; pi->writer(pi->L, &stackpos, sizeof(int), pi->ud); } /* perms reftbl ... thr */ lua_pushnil(pi->L); /* perms reftbl ... thr nil */ persist(pi); lua_pop(pi->L, 1); /* perms reftbl ... thr */ } /* perms reftbl ... thr */ }
static void unpersistthread(int ref, UnpersistInfo *upi) { /* perms reftbl ... */ lua_State *L2; L2 = lua_newthread(upi->L); /* L1: perms reftbl ... thr */ /* L2: (empty) */ registerobject(ref, upi); /* First, deserialize the object stack. */ { int i, stacksize; verify(luaZ_read(&upi->zio, &stacksize, sizeof(int)) == 0); luaD_growstack(L2, stacksize); /* Make sure that the first stack element (a nil, representing * the imaginary top-level C function) is written to the very, * very bottom of the stack */ L2->top--; for(i=0; i<stacksize; i++) { unpersist(upi); /* L1: perms reftbl ... thr obj* */ } lua_xmove(upi->L, L2, stacksize); /* L1: perms reftbl ... thr */ /* L2: obj* */ } /* Now, deserialize the CallInfo stack. */ { int i, numframes; verify(luaZ_read(&upi->zio, &numframes, sizeof(int)) == 0); luaD_reallocCI(L2,numframes*2); for(i=0; i<numframes; i++) { CallInfo *ci = L2->base_ci + i; int stackbase, stacktop, pc; verify(luaZ_read(&upi->zio, &stackbase, sizeof(int)) == 0); verify(luaZ_read(&upi->zio, &stacktop, sizeof(int)) == 0); verify(luaZ_read(&upi->zio, &pc, sizeof(int)) == 0); verify(luaZ_read(&upi->zio, &(ci->state), sizeof(int)) == 0); ci->base = L2->stack+stackbase; ci->top = L2->stack+stacktop; if(!(ci->state & CI_C)) { ci->u.l.savedpc = ci_func(ci)->l.p->code + pc; } ci->u.l.tailcalls = 0; /* Update the pointer each time, to keep the GC * happy*/ L2->ci = ci; } } /* L1: perms reftbl ... thr */ { int stackbase, stacktop; verify(luaZ_read(&upi->zio, &stackbase, sizeof(int)) == 0); verify(luaZ_read(&upi->zio, &stacktop, sizeof(int)) == 0); L2->base = L2->stack + stackbase; L2->top = L2->stack + stacktop; } /* Finally, "reopen" upvalues (see persistupval() for why) */ { UpVal* uv; GCObject **nextslot = &L2->openupval; while(1) { int stackpos; unpersist(upi); /* perms reftbl ... thr uv/nil */ if(lua_isnil(upi->L, -1)) { /* perms reftbl ... thr nil */ lua_pop(upi->L, 1); /* perms reftbl ... thr */ break; } /* perms reftbl ... thr boxeduv */ unboxupval(upi->L); /* perms reftbl ... thr uv */ uv = toupval(upi->L, -1); lua_pop(upi->L, 1); /* perms reftbl ... thr */ verify(luaZ_read(&upi->zio, &stackpos, sizeof(int)) == 0); uv->v = L2->stack + stackpos; gcunlink(upi->L, valtogco(uv)); uv->marked = 1; *nextslot = valtogco(uv); nextslot = &uv->next; } *nextslot = NULL; } }