欧美free性护士vide0shd,老熟女,一区二区三区,久久久久夜夜夜精品国产,久久久久久综合网天天,欧美成人护士h版

目錄

柚子快報(bào)激活碼778899分享:lua的數(shù)據(jù)類型,lua

柚子快報(bào)激活碼778899分享:lua的數(shù)據(jù)類型,lua

http://yzkb.51969.com/

數(shù)據(jù)類型

lua中的數(shù)據(jù)可以這樣分為兩位:值類型和引用類型。引用類型創(chuàng)建時(shí)需要從堆上分配內(nèi)存,復(fù)制時(shí)只需要復(fù)制指針,分配的內(nèi)存由GC負(fù)責(zé)維護(hù)生命期。

所有l(wèi)ua類型都用一個(gè)union來(lái)表示:

/*

** Union of all Lua values

*/

typedef union {

GCObject *gc;

void *p; /* lightuserdata */

lua_Number n;

int b; /* boolean */

} Value;

引用類型用一個(gè)gc指針來(lái)引用,其他值類型都直接保存在Value中。

每個(gè)引用類型的開(kāi)頭都是CommonHeader;,所以都可強(qiáng)轉(zhuǎn)成GCheader*使用:

/*

** Common Header for all collectable objects (in macro form, to be

** included in other objects)

*/

#define CommonHeader GCObject *next; lu_byte tt; lu_byte marked

/*

** Common header in struct form

*/

typedef struct {

CommonHeader;

} GCheader;

/*

** Union of all collectable objects

*/

union GCObject {

GCheader gch;

TString ts;

Udata u;

Closure cl;

Table h;

Proto p;

UpVal uv;

lua_State th; /* thread */

};

為了區(qū)分Value中存放的數(shù)據(jù)類型,再額外綁定一個(gè)類型字段:

/*

** Tagged Values

*/

typedef struct {

Value value;

int tt;

} TValue;

lua_State、數(shù)據(jù)棧、調(diào)用棧

lua_State表示一個(gè)線程/協(xié)程(后面線程與協(xié)程通用)的狀態(tài),lua_newstate用于創(chuàng)建主線程:

/*

** Main thread combines a thread state and the global state

*/

typedef struct {

lua_State l;

global_State g;

} LG;

LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {

int i;

lua_State *L;

global_State *g;

void *l = (*f)(ud, NULL, 0, state_size(LG));

if (l == NULL) return NULL;

...

用lua_newstate創(chuàng)建主線程的時(shí)候,同時(shí)也創(chuàng)建了一個(gè)global_State,所有的線程共享這個(gè)global_State,luaE_newthread用于創(chuàng)建協(xié)程:

lua_State *luaE_newthread (lua_State *L) {

lua_State *L1 = tostate(luaM_malloc(L, state_size(lua_State)));

luaC_link(L, obj2gco(L1), LUA_TTHREAD);

preinit_state(L1, G(L));

...

lua的數(shù)據(jù)棧是一個(gè)TValue數(shù)組,代碼中用StkId類型用來(lái)指代對(duì)TValue的引用:

typedef TValue *StkId; /* index to stack elements */

調(diào)用棧放在CallInfo數(shù)組中,CallInfo保存著正在調(diào)用的函數(shù)的運(yùn)行狀態(tài):

/*

** informations about a call

*/

typedef struct {

StkId base; /* base for this function */

StkId func; /* function index in the stack */

StkId top; /* top for this function */

const Instruction *savedpc;

int nresults; /* expected number of results from this function */

int tailcalls; /* number of tail calls lost under this entry */

} CallInfo;

正在調(diào)用的函數(shù)一定存在于數(shù)據(jù)棧上,由func引用正在調(diào)用的函數(shù)對(duì)象。 [base,top)指示了正在調(diào)用的函數(shù)的堆棧在數(shù)據(jù)棧上的范圍。 為什么沒(méi)有堆棧的當(dāng)前位置?lua_State的top就是正在調(diào)用的函數(shù)的堆棧的位置啊。

/*

** `per thread' state

*/

struct lua_State {

CommonHeader;

lu_byte status;

StkId top; /* first free slot in the stack */

StkId base; /* base of current function */

global_State *l_G;

CallInfo *ci; /* call info for current function */

const Instruction *savedpc; /* `savedpc' of current function */

StkId stack_last; /* last free slot in the stack */

StkId stack; /* stack base */

CallInfo *last_ci; /* last free slot in the ci array*/

CallInfo *base_ci; /* array of CallInfo's */

int stacksize;

int size_ci; /* size of array `base_ci' */

...

[stack,stack_last],[base_ci,last_ci]分別是數(shù)據(jù)棧數(shù)組和調(diào)用棧數(shù)組,stacksize,size_ci分別是兩個(gè)數(shù)組的大小,在需要的時(shí)候它們會(huì)進(jìn)行增長(zhǎng)。 ci是當(dāng)前正在調(diào)用的函數(shù)的運(yùn)行狀態(tài),base是該函數(shù)的棧底指針。

lua_newstate和luaE_newthread都調(diào)用了stack_init來(lái)初始化堆棧:

static void stack_init (lua_State *L1, lua_State *L) {

/* initialize CallInfo array */

L1->base_ci = luaM_newvector(L, BASIC_CI_SIZE, CallInfo);

L1->ci = L1->base_ci;

L1->size_ci = BASIC_CI_SIZE;

L1->last_ci = L1->base_ci + L1->size_ci - 1;

/* initialize stack array */

L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, TValue);

L1->stacksize = BASIC_STACK_SIZE + EXTRA_STACK;

L1->top = L1->stack;

L1->stack_last = L1->stack + (L1->stacksize - EXTRA_STACK) - 1;

/* initialize first ci */

L1->ci->func = L1->top;

setnilvalue(L1->top++); /* `function' entry for this `ci' */

L1->base = L1->ci->base = L1->top;

L1->ci->top = L1->top + LUA_MINSTACK;

}

可以看到first ci只是占了個(gè)位置,它的func只是一個(gè)空值。

c代碼中的函數(shù)調(diào)用

c代碼中調(diào)用函數(shù)(包括c函數(shù)和Lua函數(shù))使用lua_call和lua_pcall。

void (lua_call) (lua_State *L, int nargs, int nresults);

int (lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc);

在使用lua時(shí)一個(gè)愚蠢的錯(cuò)誤中同時(shí)展示了這兩個(gè)函數(shù)的用法。 二者最終都通過(guò)調(diào)用luaD_call來(lái)實(shí)現(xiàn)主要邏輯,但lua_pcall多了一層錯(cuò)誤處理機(jī)制,如果函數(shù)調(diào)用過(guò)程中出錯(cuò),lua_pcall會(huì)捕獲錯(cuò)誤,并調(diào)用用戶通過(guò)errfunc參數(shù)傳入的錯(cuò)誤處理函數(shù),而lua_call則會(huì)直接退出程序。這套錯(cuò)誤處理機(jī)制是通過(guò)c的longjmp或c++的異常機(jī)制來(lái)實(shí)現(xiàn)的。

/*

** 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);

}

luaD_precall執(zhí)行的是函數(shù)調(diào)用部分的工作,而luaD_poscall做的是函數(shù)返回的工作。對(duì)于c函數(shù)整個(gè)函數(shù)調(diào)用是連續(xù)的,luaD_precall在調(diào)用完c函數(shù)后可直接調(diào)用luaD_poscall完成工作;而lua函數(shù)執(zhí)行完luaD_precall后,只是切換了lua_State的執(zhí)行狀態(tài),被調(diào)用的函數(shù)的字節(jié)碼尚未運(yùn)行,luaD_precall返回后,調(diào)用luaV_execute去運(yùn)行被調(diào)用函數(shù)的字節(jié)碼,待到虛擬機(jī)執(zhí)行到對(duì)應(yīng)的return指令時(shí),才會(huì)去調(diào)用luaD_poscall完成整次調(diào)用。

c函數(shù)的參數(shù)傳遞

使用lua_call或lua_pcall調(diào)用lua函數(shù)前,應(yīng)先在棧上準(zhǔn)備好函數(shù)對(duì)象和函數(shù)的參數(shù),如果沒(méi)有錯(cuò)誤發(fā)生,函數(shù)返回時(shí),函數(shù)對(duì)象和函數(shù)參數(shù)會(huì)出棧,函數(shù)的返回值會(huì)留在棧上。 而如果調(diào)用的是c函數(shù)時(shí),一般是先通過(guò)lua_pushcclosure來(lái)創(chuàng)建c閉包,然后再調(diào)用lua_call或lua_pcall。

void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {

Closure *cl;

lua_lock(L);

luaC_checkGC(L);

api_checknelems(L, n);

cl = luaF_newCclosure(L, n, getcurrenv(L));

cl->c.f = fn;

L->top -= n;

while (n--)

setobj2n(L, &cl->c.upvalue[n], L->top+n);

setclvalue(L, L->top, cl);

lua_assert(iswhite(obj2gco(cl)));

api_incr_top(L);

lua_unlock(L);

}

調(diào)用lua_pushcclosure前,fn需要的參數(shù)都在棧上,lua_pushcclosure會(huì)把棧上的參數(shù)轉(zhuǎn)移到c閉包的上值中,然后把c閉包壓入棧。在函數(shù)fn中,需要用lua_getupvalue來(lái)讀取參數(shù)。

lua還提供了另一種調(diào)用c函數(shù)的方式:

int lua_cpcall (lua_State *L, lua_CFunction func, void *ud);

在調(diào)用lua_cpcall前,不需要將參數(shù)壓入棧,而是直接將參數(shù)通過(guò)ud傳遞給lua_cpcall。 lua_cpcall會(huì)創(chuàng)建一個(gè)沒(méi)有上值的c閉包并壓入棧中,然后將ud作為lightuserdata也壓入棧,其余便和lua_pcall類似了。 在函數(shù)func中需要通過(guò)lua_touserdata取出參數(shù)。 lua_cpcall在調(diào)用luaD_call時(shí)nResults傳入的是0,所以func并沒(méi)有返回值。

協(xié)程

協(xié)程的創(chuàng)建就是新建了一個(gè)lua_State,然后將lua函數(shù)對(duì)象移到新建的lua_State上:

int luaB_cocreate (lua_State *L) {

lua_State *NL = lua_newthread(L);

luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1,

"Lua function expected");

lua_pushvalue(L, 1); /* move function to top */

lua_xmove(L, NL, 1); /* move function from L to NL */

return 1;

}

通過(guò)luaB_coresume啟動(dòng)/恢復(fù)協(xié)程,首個(gè)參數(shù)是協(xié)程對(duì)象:

static int luaB_coresume (lua_State *L) {

lua_State *co = lua_tothread(L, 1);

int r;

luaL_argcheck(L, co, 1, "coroutine expected");

r = auxresume(L, co, lua_gettop(L) - 1);

if (r < 0) {

lua_pushboolean(L, 0);

lua_insert(L, -2);

return 2; /* return false + error message */

}

else {

lua_pushboolean(L, 1);

lua_insert(L, -(r + 1));

return r + 1; /* return true + `resume' returns */

}

}

在auxresume中將coroutine.resume的其余參數(shù)從主線程轉(zhuǎn)移至協(xié)程:

int auxresume (lua_State *L, lua_State *co, int narg) {

int status = costatus(L, co);

if (!lua_checkstack(co, narg))

luaL_error(L, "too many arguments to resume");

if (status != CO_SUS) {

lua_pushfstring(L, "cannot resume %s coroutine", statnames[status]);

return -1; /* error flag */

}

lua_xmove(L, co, narg);

lua_setlevel(L, co);

status = lua_resume(co, narg);

...

然后去調(diào)用lua_resume,后續(xù)最終會(huì)調(diào)用resume:

void resume (lua_State *co, void *ud) {

StkId firstArg = cast(StkId, ud);

CallInfo *ci = co->ci;

if (co->status == 0) { /* start coroutine? */

lua_assert(ci == co->base_ci && firstArg - co->base == 1);

lua_assert(isLfunction(co->base));

if (luaD_precall(co, firstArg - 1, LUA_MULTRET) != PCRLUA)

return;

}

else { /* resuming from previous yield */

lua_assert(co->status == LUA_YIELD);

co->status = 0;

if (!f_isLua(ci)) { /* `common' yield? */

/* finish interrupted execution of `OP_CALL' */

lua_assert(GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_CALL ||

GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_TAILCALL);

if (luaD_poscall(co, firstArg)) /* complete it... */

co->top = co->ci->top; /* and correct top if not multiple results */

}

else /* yielded inside a hook: just continue its execution */

co->base = co->ci->base;

}

luaV_execute(co, cast_int(co->ci - co->base_ci));

}

啟動(dòng)協(xié)程時(shí),和調(diào)用普通lua函數(shù)一樣先調(diào)用luaD_precall,再調(diào)用luaV_execute,luaV_execute中調(diào)用函數(shù)的代碼如下:

void luaV_execute (lua_State *L, int nexeccalls) {

...

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 */

}

}

}

...

}

int luaD_precall (lua_State *L, StkId func, int nresults) {

...

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 = (*ci_func(ci)->c.f)(L); /* do the actual call */

lua_lock(L);

if (n < 0) /* yielding? */

return PCRYIELD;

else {

// n表示c函數(shù)留在棧上的結(jié)果數(shù)量,luaD_poscall會(huì)將結(jié)果調(diào)整為nresults個(gè),放到func開(kāi)始的位置

// 相當(dāng)于將func和所有參數(shù)出棧,再將前nresults的返回值入棧

luaD_poscall(L, L->top - n);

return PCRC;

}

}

...

}

當(dāng)lua函數(shù)中碰到coroutine.yield時(shí),經(jīng)luaD_precall->luaB_yield,再調(diào)用到lua_yield:

int lua_yield (lua_State *co, int nresults) {

luai_userstateyield(co, nresults);

lua_lock(co);

if (co->nCcalls > co->baseCcalls)

luaG_runerror(co, "attempt to yield across metamethod/C-call boundary");

co->base = co->top - nresults; /* protect stack slots below */

co->status = LUA_YIELD;

lua_unlock(co);

return -1;

}

lua_yield將協(xié)程置為L(zhǎng)UA_YIELD狀態(tài),設(shè)置了co->base,然后一路返回到auxresume:

static int auxresume (lua_State *L, lua_State *co, int narg) {

...

status = lua_resume(co, narg);

if (status == 0 || status == LUA_YIELD) {

int nres = lua_gettop(co);

if (!lua_checkstack(L, nres + 1))

luaL_error(L, "too many results to resume");

lua_xmove(co, L, nres); /* move yielded values */

return nres;

}

else {

lua_xmove(co, L, 1); /* move error message */

return -1; /* error flag */

}

}

因?yàn)閘ua_yield設(shè)置的co->base,lua_gettop(co)返回coroutine.yield的參數(shù)個(gè)數(shù),將這些參數(shù)轉(zhuǎn)移到主線程后,便從coroutine.resume返回了。

注意到luaD_precall中發(fā)生yield時(shí),并沒(méi)有調(diào)用luaD_poscall,當(dāng)協(xié)程恢復(fù)時(shí)調(diào)用luaD_poscall相當(dāng)于把coroutine.resume的參數(shù)做為coroutine.yield的返回值,完成coroutine.yield的調(diào)用。通過(guò)這個(gè)流程就可以看出yield不能跨c函數(shù)。

柚子快報(bào)激活碼778899分享:lua的數(shù)據(jù)類型,lua

http://yzkb.51969.com/

推薦閱讀

評(píng)論可見(jiàn),查看隱藏內(nèi)容

本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。

轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。

本文鏈接:http://gantiao.com.cn/post/19601681.html

發(fā)布評(píng)論

您暫未設(shè)置收款碼

請(qǐng)?jiān)谥黝}配置——文章設(shè)置里上傳

掃描二維碼手機(jī)訪問(wèn)

文章目錄