这是从lua-5.1.1中分离出来的vm实现代码。
Last active
May 28, 2021 13:44
-
-
Save losophy/2a7afe87b4b4e685e849c3d04f738732 to your computer and use it in GitHub Desktop.
lua-5.1.1中的vm的实现
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
static void f_parser (lua_State *L, void *ud) { | |
int i; | |
Proto *tf; | |
Closure *cl; | |
struct SParser *p = cast(struct SParser *, ud); | |
int c = luaZ_lookahead(p->z); | |
luaC_checkGC(L); | |
tf = ((c == LUA_SIGNATURE[0]) ? luaU_undump : luaY_parser)(L, p->z, | |
&p->buff, p->name); | |
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); | |
} | |
LUA_API int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc) { | |
struct CallS c; | |
int status; | |
ptrdiff_t func; | |
lua_lock(L); | |
api_checknelems(L, nargs+1); | |
checkresults(L, nargs, nresults); | |
if (errfunc == 0) | |
func = 0; | |
else { | |
StkId o = index2adr(L, errfunc); | |
api_checkvalidindex(L, o); | |
func = savestack(L, o); | |
} | |
c.func = L->top - (nargs+1); //获取需要调用的函数指针 | |
c.nresults = nresults; | |
status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func); | |
adjustresults(L, nresults); | |
lua_unlock(L); | |
return status; | |
} | |
/* | |
** 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, all the results are on the stack, starting at the original | |
** function position. | |
*/ | |
void luaD_call (lua_State *L, StkId func, int nResults) { | |
if (++L->nCcalls >= LUAI_MAXCCALLS) { | |
if (L->nCcalls == LUAI_MAXCCALLS) | |
luaG_runerror(L, "C stack overflow"); | |
else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) | |
luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ | |
} | |
if (luaD_precall(L, func, nResults) == PCRLUA) /* is a Lua function? */ | |
luaV_execute(L, 1); /* call it */ | |
L->nCcalls--; | |
luaC_checkGC(L); | |
} | |
int luaD_precall (lua_State *L, StkId func, int nresults) { | |
LClosure *cl; | |
ptrdiff_t funcr; | |
if (!ttisfunction(func)) /* `func' is not a function? */ | |
func = tryfuncTM(L, func); /* check the `function' tag method */ | |
funcr = savestack(L, func); | |
cl = &clvalue(func)->l; | |
L->ci->savedpc = L->savedpc; | |
if (!cl->isC) { /* Lua function? prepare its call */ | |
CallInfo *ci; | |
StkId st, base; | |
Proto *p = cl->p; | |
luaD_checkstack(L, p->maxstacksize); | |
func = restorestack(L, funcr); | |
if (!p->is_vararg) { /* no varargs? */ | |
base = func + 1; | |
if (L->top > base + p->numparams) | |
L->top = base + p->numparams; | |
} | |
else { /* vararg function */ | |
int nargs = cast_int(L->top - func) - 1; | |
base = adjust_varargs(L, p, nargs); | |
func = restorestack(L, funcr); /* previous call may change the stack */ | |
} | |
ci = inc_ci(L); /* now `enter' new function */ | |
ci->func = func; | |
L->base = ci->base = base; | |
ci->top = L->base + p->maxstacksize; | |
lua_assert(ci->top <= L->stack_last); | |
L->savedpc = p->code; /* starting point */ | |
ci->tailcalls = 0; | |
ci->nresults = nresults; | |
for (st = L->top; st < ci->top; st++) | |
setnilvalue(st); | |
L->top = ci->top; | |
if (L->hookmask & LUA_MASKCALL) { | |
L->savedpc++; /* hooks assume 'pc' is already incremented */ | |
luaD_callhook(L, LUA_HOOKCALL, -1); | |
L->savedpc--; /* correct 'pc' */ | |
} | |
return PCRLUA; | |
} | |
else { /* if is a C function, call it */ | |
CallInfo *ci; | |
int n; | |
luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ | |
ci = inc_ci(L); /* now `enter' new function */ | |
ci->func = restorestack(L, funcr); | |
L->base = ci->base = ci->func + 1; | |
ci->top = L->top + LUA_MINSTACK; | |
lua_assert(ci->top <= L->stack_last); | |
ci->nresults = nresults; | |
if (L->hookmask & LUA_MASKCALL) | |
luaD_callhook(L, LUA_HOOKCALL, -1); | |
lua_unlock(L); | |
n = (*curr_func(L)->c.f)(L); /* do the actual call */ | |
lua_lock(L); | |
if (n < 0) /* yielding? */ | |
return PCRYIELD; | |
else { | |
luaD_poscall(L, L->top - n); | |
return PCRC; | |
} | |
} | |
} | |
void luaV_execute (lua_State *L, int nexeccalls) { | |
LClosure *cl; | |
StkId base; | |
TValue *k; | |
const Instruction *pc; | |
reentry: /* entry point */ | |
lua_assert(isLua(L->ci)); | |
pc = L->savedpc; | |
cl = &clvalue(L->ci->func)->l; | |
base = L->base; | |
k = cl->p->k; | |
/* main loop of interpreter */ | |
for (;;) { | |
const Instruction i = *pc++; | |
StkId ra; | |
if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && | |
(--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { | |
traceexec(L, pc); | |
if (L->status == LUA_YIELD) { /* did hook yield? */ | |
L->savedpc = pc - 1; | |
return; | |
} | |
base = L->base; | |
} | |
/* warning!! several calls may realloc the stack and invalidate `ra' */ | |
ra = RA(i); | |
lua_assert(base == L->base && L->base == L->ci->base); | |
lua_assert(base <= L->top && L->top <= L->stack + L->stacksize); | |
lua_assert(L->top == L->ci->top || luaG_checkopenop(i)); | |
switch (GET_OPCODE(i)) { | |
case OP_MOVE: { | |
setobjs2s(L, ra, RB(i)); | |
continue; | |
} | |
case OP_LOADK: { | |
setobj2s(L, ra, KBx(i)); | |
continue; | |
} | |
case OP_LOADBOOL: { | |
setbvalue(ra, GETARG_B(i)); | |
if (GETARG_C(i)) pc++; /* skip next instruction (if C) */ | |
continue; | |
} | |
case OP_LOADNIL: { | |
TValue *rb = RB(i); | |
do { | |
setnilvalue(rb--); | |
} while (rb >= ra); | |
continue; | |
} | |
case OP_GETUPVAL: { | |
int b = GETARG_B(i); | |
setobj2s(L, ra, cl->upvals[b]->v); | |
continue; | |
} | |
case OP_GETGLOBAL: { | |
TValue g; | |
TValue *rb = KBx(i); | |
sethvalue(L, &g, cl->env); | |
lua_assert(ttisstring(rb)); | |
Protect(luaV_gettable(L, &g, rb, ra)); | |
continue; | |
} | |
case OP_GETTABLE: { | |
Protect(luaV_gettable(L, RB(i), RKC(i), ra)); | |
continue; | |
} | |
case OP_SETGLOBAL: { | |
TValue g; | |
sethvalue(L, &g, cl->env); | |
lua_assert(ttisstring(KBx(i))); | |
Protect(luaV_settable(L, &g, KBx(i), ra)); | |
continue; | |
} | |
case OP_SETUPVAL: { | |
UpVal *uv = cl->upvals[GETARG_B(i)]; | |
setobj(L, uv->v, ra); | |
luaC_barrier(L, uv, ra); | |
continue; | |
} | |
case OP_SETTABLE: { | |
Protect(luaV_settable(L, ra, RKB(i), RKC(i))); | |
continue; | |
} | |
case OP_NEWTABLE: { | |
int b = GETARG_B(i); | |
int c = GETARG_C(i); | |
sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c))); | |
Protect(luaC_checkGC(L)); | |
continue; | |
} | |
case OP_SELF: { | |
StkId rb = RB(i); | |
setobjs2s(L, ra+1, rb); | |
Protect(luaV_gettable(L, rb, RKC(i), ra)); | |
continue; | |
} | |
case OP_ADD: { | |
arith_op(luai_numadd, TM_ADD); | |
continue; | |
} | |
case OP_SUB: { | |
arith_op(luai_numsub, TM_SUB); | |
continue; | |
} | |
case OP_MUL: { | |
arith_op(luai_nummul, TM_MUL); | |
continue; | |
} | |
case OP_DIV: { | |
arith_op(luai_numdiv, TM_DIV); | |
continue; | |
} | |
case OP_MOD: { | |
arith_op(luai_nummod, TM_MOD); | |
continue; | |
} | |
case OP_POW: { | |
arith_op(luai_numpow, TM_POW); | |
continue; | |
} | |
case OP_UNM: { | |
TValue *rb = RB(i); | |
if (ttisnumber(rb)) { | |
lua_Number nb = nvalue(rb); | |
setnvalue(ra, luai_numunm(nb)); | |
} | |
else { | |
Protect(Arith(L, ra, rb, rb, TM_UNM)); | |
} | |
continue; | |
} | |
case OP_NOT: { | |
int res = l_isfalse(RB(i)); /* next assignment may change this value */ | |
setbvalue(ra, res); | |
continue; | |
} | |
case OP_LEN: { | |
const TValue *rb = RB(i); | |
switch (ttype(rb)) { | |
case LUA_TTABLE: { | |
setnvalue(ra, cast_num(luaH_getn(hvalue(rb)))); | |
break; | |
} | |
case LUA_TSTRING: { | |
setnvalue(ra, cast_num(tsvalue(rb)->len)); | |
break; | |
} | |
default: { /* try metamethod */ | |
Protect( | |
if (!call_binTM(L, rb, luaO_nilobject, ra, TM_LEN)) | |
luaG_typeerror(L, rb, "get length of"); | |
) | |
} | |
} | |
continue; | |
} | |
case OP_CONCAT: { | |
int b = GETARG_B(i); | |
int c = GETARG_C(i); | |
Protect(luaV_concat(L, c-b+1, c); luaC_checkGC(L)); | |
setobjs2s(L, RA(i), base+b); | |
continue; | |
} | |
case OP_JMP: { | |
dojump(L, pc, GETARG_sBx(i)); | |
continue; | |
} | |
case OP_EQ: { | |
TValue *rb = RKB(i); | |
TValue *rc = RKC(i); | |
Protect( | |
if (equalobj(L, rb, rc) == GETARG_A(i)) | |
dojump(L, pc, GETARG_sBx(*pc)); | |
) | |
pc++; | |
continue; | |
} | |
case OP_LT: { | |
Protect( | |
if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i)) | |
dojump(L, pc, GETARG_sBx(*pc)); | |
) | |
pc++; | |
continue; | |
} | |
case OP_LE: { | |
Protect( | |
if (lessequal(L, RKB(i), RKC(i)) == GETARG_A(i)) | |
dojump(L, pc, GETARG_sBx(*pc)); | |
) | |
pc++; | |
continue; | |
} | |
case OP_TEST: { | |
if (l_isfalse(ra) != GETARG_C(i)) | |
dojump(L, pc, GETARG_sBx(*pc)); | |
pc++; | |
continue; | |
} | |
case OP_TESTSET: { | |
TValue *rb = RB(i); | |
if (l_isfalse(rb) != GETARG_C(i)) { | |
setobjs2s(L, ra, rb); | |
dojump(L, pc, GETARG_sBx(*pc)); | |
} | |
pc++; | |
continue; | |
} | |
case OP_CALL: { | |
int b = GETARG_B(i); | |
int nresults = GETARG_C(i) - 1; | |
if (b != 0) L->top = ra+b; /* else previous instruction set top */ | |
L->savedpc = pc; | |
switch (luaD_precall(L, ra, nresults)) { | |
case PCRLUA: { | |
nexeccalls++; | |
goto reentry; /* restart luaV_execute over new Lua function */ | |
} | |
case PCRC: { | |
/* it was a C function (`precall' called it); adjust results */ | |
if (nresults >= 0) L->top = L->ci->top; | |
base = L->base; | |
continue; | |
} | |
default: { | |
return; /* yield */ | |
} | |
} | |
} | |
case OP_TAILCALL: { | |
int b = GETARG_B(i); | |
if (b != 0) L->top = ra+b; /* else previous instruction set top */ | |
L->savedpc = pc; | |
lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); | |
switch (luaD_precall(L, ra, LUA_MULTRET)) { | |
case PCRLUA: { | |
/* tail call: put new frame in place of previous one */ | |
CallInfo *ci = L->ci - 1; /* previous frame */ | |
int aux; | |
StkId func = ci->func; | |
StkId pfunc = (ci+1)->func; /* previous function index */ | |
if (L->openupval) luaF_close(L, ci->base); | |
L->base = ci->base = ci->func + ((ci+1)->base - pfunc); | |
for (aux = 0; pfunc+aux < L->top; aux++) /* move frame down */ | |
setobjs2s(L, func+aux, pfunc+aux); | |
ci->top = L->top = func+aux; /* correct top */ | |
lua_assert(L->top == L->base + clvalue(func)->l.p->maxstacksize); | |
ci->savedpc = L->savedpc; | |
ci->tailcalls++; /* one more call lost */ | |
L->ci--; /* remove new frame */ | |
goto reentry; | |
} | |
case PCRC: { /* it was a C function (`precall' called it) */ | |
base = L->base; | |
continue; | |
} | |
default: { | |
return; /* yield */ | |
} | |
} | |
} | |
case OP_RETURN: { | |
int b = GETARG_B(i); | |
if (b != 0) L->top = ra+b-1; | |
if (L->openupval) luaF_close(L, base); | |
L->savedpc = pc; | |
b = luaD_poscall(L, ra); | |
if (--nexeccalls == 0) /* was previous function running `here'? */ | |
return; /* no: return */ | |
else { /* yes: continue its execution */ | |
if (b) L->top = L->ci->top; | |
lua_assert(isLua(L->ci)); | |
lua_assert(GET_OPCODE(*((L->ci)->savedpc - 1)) == OP_CALL); | |
goto reentry; | |
} | |
} | |
case OP_FORLOOP: { | |
lua_Number step = nvalue(ra+2); | |
lua_Number idx = luai_numadd(nvalue(ra), step); /* increment index */ | |
lua_Number limit = nvalue(ra+1); | |
if (luai_numlt(0, step) ? luai_numle(idx, limit) | |
: luai_numle(limit, idx)) { | |
dojump(L, pc, GETARG_sBx(i)); /* jump back */ | |
setnvalue(ra, idx); /* update internal index... */ | |
setnvalue(ra+3, idx); /* ...and external index */ | |
} | |
continue; | |
} | |
case OP_FORPREP: { | |
const TValue *init = ra; | |
const TValue *plimit = ra+1; | |
const TValue *pstep = ra+2; | |
L->savedpc = pc; /* next steps may throw errors */ | |
if (!tonumber(init, ra)) | |
luaG_runerror(L, LUA_QL("for") " initial value must be a number"); | |
else if (!tonumber(plimit, ra+1)) | |
luaG_runerror(L, LUA_QL("for") " limit must be a number"); | |
else if (!tonumber(pstep, ra+2)) | |
luaG_runerror(L, LUA_QL("for") " step must be a number"); | |
setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep))); | |
dojump(L, pc, GETARG_sBx(i)); | |
continue; | |
} | |
case OP_TFORLOOP: { | |
StkId cb = ra + 3; /* call base */ | |
setobjs2s(L, cb+2, ra+2); | |
setobjs2s(L, cb+1, ra+1); | |
setobjs2s(L, cb, ra); | |
L->top = cb+3; /* func. + 2 args (state and index) */ | |
Protect(luaD_call(L, cb, GETARG_C(i))); | |
L->top = L->ci->top; | |
cb = RA(i) + 3; /* previous call may change the stack */ | |
if (!ttisnil(cb)) { /* continue loop? */ | |
setobjs2s(L, cb-1, cb); /* save control variable */ | |
dojump(L, pc, GETARG_sBx(*pc)); /* jump back */ | |
} | |
pc++; | |
continue; | |
} | |
case OP_SETLIST: { | |
int n = GETARG_B(i); | |
int c = GETARG_C(i); | |
int last; | |
Table *h; | |
if (n == 0) { | |
n = cast_int(L->top - ra) - 1; | |
L->top = L->ci->top; | |
} | |
if (c == 0) c = cast_int(*pc++); | |
runtime_check(L, ttistable(ra)); | |
h = hvalue(ra); | |
last = ((c-1)*LFIELDS_PER_FLUSH) + n; | |
if (last > h->sizearray) /* needs more space? */ | |
luaH_resizearray(L, h, last); /* pre-alloc it at once */ | |
for (; n > 0; n--) { | |
TValue *val = ra+n; | |
setobj2t(L, luaH_setnum(L, h, last--), val); | |
luaC_barriert(L, h, val); | |
} | |
continue; | |
} | |
case OP_CLOSE: { | |
luaF_close(L, ra); | |
continue; | |
} | |
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->env); | |
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(L, ra, ncl); | |
Protect(luaC_checkGC(L)); | |
continue; | |
} | |
case OP_VARARG: { | |
int b = GETARG_B(i) - 1; | |
int j; | |
CallInfo *ci = L->ci; | |
int n = cast_int(ci->base - ci->func) - cl->p->numparams - 1; | |
if (b == LUA_MULTRET) { | |
Protect(luaD_checkstack(L, n)); | |
ra = RA(i); /* previous call may change the stack */ | |
b = n; | |
L->top = ra + n; | |
} | |
for (j = 0; j < b; j++) { | |
if (j < n) { | |
setobjs2s(L, ra + j, ci->base - n + j); | |
} | |
else { | |
setnilvalue(ra + j); | |
} | |
} | |
continue; | |
} | |
} | |
} | |
} | |
int luaD_poscall (lua_State *L, StkId firstResult) { | |
StkId res; | |
int wanted, i; | |
CallInfo *ci; | |
if (L->hookmask & LUA_MASKRET) | |
firstResult = callrethooks(L, firstResult); | |
ci = L->ci--; | |
res = ci->func; /* res == final position of 1st result */ | |
wanted = ci->nresults; | |
L->base = (ci - 1)->base; /* restore base */ | |
L->savedpc = (ci - 1)->savedpc; /* restore savedpc */ | |
/* move results to correct place */ | |
for (i = wanted; i != 0 && firstResult < L->top; i--) | |
setobjs2s(L, res++, firstResult++); | |
while (i-- > 0) | |
setnilvalue(res++); | |
L->top = res; | |
return (wanted - LUA_MULTRET); /* 0 iff wanted == LUA_MULTRET */ | |
} | |
Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, const char *name) { | |
struct LexState lexstate; | |
struct FuncState funcstate; | |
lexstate.buff = buff; | |
luaX_setinput(L, &lexstate, z, luaS_new(L, name)); | |
open_func(&lexstate, &funcstate); | |
funcstate.f->is_vararg = VARARG_ISVARARG; /* main func. is always vararg */ | |
luaX_next(&lexstate); /* read first token */ | |
chunk(&lexstate); | |
check(&lexstate, TK_EOS); | |
close_func(&lexstate); | |
lua_assert(funcstate.prev == NULL); | |
lua_assert(funcstate.f->nups == 0); | |
lua_assert(lexstate.fs == NULL); | |
return funcstate.f; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define luaL_dofile(L, fn) \ | |
(luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0)) | |
/* | |
** Function Prototypes | |
*/ | |
typedef struct Proto { | |
CommonHeader; | |
TValue *k; //函数的常量数组 | |
Instruction *code;//编译生成的字节码信息,也就是前面提到的 code成员 | |
struct Proto **p; /* functions defined inside the function */ | |
int *lineinfo; /* map from opcodes to source lines */ | |
struct LocVar *locvars; //函数的局部变量信息 | |
TString **upvalues; //保存upvalue的数组 | |
... | |
} Proto; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment