我自认为的 Lua 5.3.4 主函数执行过程
在这里,我说的 Lua 主函数主要指的是 lua.c
里面的 main
函数,我也不知道有没有专门的描述指向这个,就暂时这么理解吧。
- main(lua.c#L596)
- lua_State *L = luaL_newstate(lauxlib.c#L1026)(); 用于 create state
- lua_newstate(lstate.c#295) 官方的说法:The auxiliary library provides several convenient functions to interface C with Lua。在这里真正创建 state 的是 lstate.c 的 lua_newstate,而这个函数要求传进来的其中一个参数是
lua_Alloc f
,luaxlib 传进来的是 l_alloc(lauxlib.c#1008)(这个函数是 static 的,所以只能在 lauxlib.c 里面使用)- 用传进来的
lua_Alloc f
方法指针来创建一个 LG) 结构体,用来记录 LX l 跟 global_state g。而 LX 里面会记录一个lu_byte extra_[LUA_EXTRASPACE]
(这个是目测是用来提供给用户使用的,Lua 并不会用这部分的空姐)和一个 lua_State。而在lua_State
里面记录了一个 CommonHeader(这个主要是用于 GC 通用的数据)。 - 设置一些 GC 的属性,L->next,L->tt,g->currentwhite,L->marked
- preinit_thread
- 设置 global 的属性
- 调用 luaD_rawrunprotected 来执行 f_luaopen,luaD_rawrunprotected 主要就是维护
errorJmp
,把它们串起来,我想大概就可以是为了抛出错误类似那样的功能。- 记录
L->nCcalls
- 设置 lua_longjmp 结构的 lj 的
status
和previous
,并把当前的L->errorJmp
设置成 lj - 用 LUAI_TRY 调用 f_luaopen,所以以下是 f_luaopen 的执行过程了
- stack_init(L, L)
- 调用 luaM_newvector(L, BASIC_STACK_SIZE, TValue) 创建 BASIC_STACK_SIZE TValue 的 vector
- luaM_reallocv 这里增加一些检查
- luaM_realloc_ 真实分配空间
- luaM_reallocv 这里增加一些检查
- 设置 L 中 stack 相关属性
L->stack
,L->stacksize
,L->top
,L->stack_last
- 初始化第一个 CallInfo
L1->ci
- 调用 luaM_newvector(L, BASIC_STACK_SIZE, TValue) 创建 BASIC_STACK_SIZE TValue 的 vector
- init_registry(L, g)
- Table *registry = luaH_new(L)
- luaC_newobj(L, LUA_TTABLE, sizeof(Table))
- luaM_newobject(L, novariant(tt), sz),留意这里返回的结果会 cast 成 GCObject,然后这是它的 gc 相关属性
- gco2t(o)
- 设置 Table t 的相关属性
metatable
,flags
,array
,sizearay
- luaC_newobj(L, LUA_TTABLE, sizeof(Table))
- sethvalue(L, &g->l_registry, registry)
- luaH_resize(L, registry, LUA_RIDX_LAST, 0)
- 设置 registry[LUA_RIDX_MAINTHREAD] 记录 L
- 设置 registry[LUA_RIDX_GLOBALS] 记录一个 Table
- Table *registry = luaH_new(L)
- luaS_init(#luas_initlstringc113)(L) 初始化字符串 Table
- luaT_init(#luat_initltmc37)(L) 初始化 Tag Method 相关
- luaX_init(#luax_initllexc70)(L) 初始化 Lexical Tokens
- g->gcrunning = 1; /* allow gc */
- g->version = lua_version(#lua_versionlapic144)(NULL); 初始化 version
- luai_userstateopen(#luai_userstateopenllimitsh227)(L); 这里可以通过自己定义 luai_userstateopen 宏来覆盖
- stack_init(L, L)
- 恢复
L->errorJmp
和L->nCcalls
,返回lj.status
- 记录
- 用传进来的
- if (L) lua_atpanic(L, &panic);
- lua_newstate(lstate.c#295) 官方的说法:The auxiliary library provides several convenient functions to interface C with Lua。在这里真正创建 state 的是 lstate.c 的 lua_newstate,而这个函数要求传进来的其中一个参数是
- lua_pushcfunction(L, &pmain); /* to call ‘pmain’ in protected mode */
- lua_pushcclosure(L, (f), 0)
- setfvalue(L->top, fn);
- api_incr_top(L); 检查 L-> top 是否超出了 L->ci->top
- luaC_checkGC(L);
- luaC_condGC(L,(void)0,(void)0)
- luaC_step(L) 此处 GC 内容还是很多的,需要再开坑聊了
- luaC_condGC(L,(void)0,(void)0)
- lua_pushcclosure(L, (f), 0)
- lua_pushinteger(L, argc); /* 1st argument */
- lua_pushlightuserdata(L, argv); /* 2nd argument */
- status = lua_pcall(L, 2, 1, 0); /* do the call */
- lua_pcallk(L, (n), (r), (f), 0, NULL)
- api_checknelems(L, nargs+1);
- luaD_pcall(L, f_call, &c, savestack(L, c.func), func);
- luaD_rawrunprotected(L, func, u); 这里会调用 pmain 方法(在之前 push 到栈里面的),pmain 会根据参数来选择执行。
- lua_State *L = luaL_newstate(lauxlib.c#L1026)(); 用于 create state
main(lua.c#L596)
int main (int argc, char **argv) {
int status, result;
lua_State *L = luaL_newstate(); /* create state */
if (L == NULL) {
l_message(argv[0], "cannot create state: not enough memory");
return EXIT_FAILURE;
}
lua_pushcfunction(L, &pmain); /* to call 'pmain' in protected mode */
lua_pushinteger(L, argc); /* 1st argument */
lua_pushlightuserdata(L, argv); /* 2nd argument */
status = lua_pcall(L, 2, 1, 0); /* do the call */
result = lua_toboolean(L, -1); /* get result */
report(L, status);
lua_close(L);
return (result && status == LUA_OK) ? EXIT_SUCCESS : EXIT_FAILURE;
}
luaL_newstate(lauxlib.c#L1026)
LUALIB_API lua_State *luaL_newstate (void) {
lua_State *L = lua_newstate(l_alloc, NULL);
if (L) lua_atpanic(L, &panic);
return L;
}
lua_newstate(lstate.c#295)
LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
int i;
lua_State *L;
global_State *g;
LG *l = cast(LG *, (*f)(ud, NULL, LUA_TTHREAD, sizeof(LG)));
if (l == NULL) return NULL;
L = &l->l.l;
g = &l->g;
L->next = NULL;
L->tt = LUA_TTHREAD;
g->currentwhite = bitmask(WHITE0BIT);
L->marked = luaC_white(g);
preinit_thread(L, g);
g->frealloc = f;
g->ud = ud;
g->mainthread = L;
g->seed = makeseed(L);
g->gcrunning = 0; /* no GC while building state */
g->GCestimate = 0;
g->strt.size = g->strt.nuse = 0;
g->strt.hash = NULL;
setnilvalue(&g->l_registry);
g->panic = NULL;
g->version = NULL;
g->gcstate = GCSpause;
g->gckind = KGC_NORMAL;
g->allgc = g->finobj = g->tobefnz = g->fixedgc = NULL;
g->sweepgc = NULL;
g->gray = g->grayagain = NULL;
g->weak = g->ephemeron = g->allweak = NULL;
g->twups = NULL;
g->totalbytes = sizeof(LG);
g->GCdebt = 0;
g->gcfinnum = 0;
g->gcpause = LUAI_GCPAUSE;
g->gcstepmul = LUAI_GCMUL;
for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL;
if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) {
/* memory allocation error: free partial state */
close_state(L);
L = NULL;
}
return L;
}
l_alloc(lauxlib.c#1008)
static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
(void)ud; (void)osize; /* not used */
if (nsize == 0) {
free(ptr);
return NULL;
}
else
return realloc(ptr, nsize);
}
LG(lstate.c#63)
/*
** Main thread combines a thread state and the global state
*/
typedef struct LG {
LX l;
global_State g;
} LG;
LX(lstate.c#54)
/*
** thread state + extra space
*/
typedef struct LX {
lu_byte extra_[LUA_EXTRASPACE];
lua_State l;
} LX;
global_state(lstate.h#119)
/*
** 'global state', shared by all threads of this state
*/
typedef struct global_State {
lua_Alloc frealloc; /* function to reallocate memory */
void *ud; /* auxiliary data to 'frealloc' */
l_mem totalbytes; /* number of bytes currently allocated - GCdebt */
l_mem GCdebt; /* bytes allocated not yet compensated by the collector */
lu_mem GCmemtrav; /* memory traversed by the GC */
lu_mem GCestimate; /* an estimate of the non-garbage memory in use */
stringtable strt; /* hash table for strings */
TValue l_registry;
unsigned int seed; /* randomized seed for hashes */
lu_byte currentwhite;
lu_byte gcstate; /* state of garbage collector */
lu_byte gckind; /* kind of GC running */
lu_byte gcrunning; /* true if GC is running */
GCObject *allgc; /* list of all collectable objects */
GCObject **sweepgc; /* current position of sweep in list */
GCObject *finobj; /* list of collectable objects with finalizers */
GCObject *gray; /* list of gray objects */
GCObject *grayagain; /* list of objects to be traversed atomically */
GCObject *weak; /* list of tables with weak values */
GCObject *ephemeron; /* list of ephemeron tables (weak keys) */
GCObject *allweak; /* list of all-weak tables */
GCObject *tobefnz; /* list of userdata to be GC */
GCObject *fixedgc; /* list of objects not to be collected */
struct lua_State *twups; /* list of threads with open upvalues */
unsigned int gcfinnum; /* number of finalizers to call in each GC step */
int gcpause; /* size of pause between successive GCs */
int gcstepmul; /* GC 'granularity' */
lua_CFunction panic; /* to be called in unprotected errors */
struct lua_State *mainthread;
const lua_Number *version; /* pointer to version number */
TString *memerrmsg; /* memory-error message */
TString *tmname[TM_N]; /* array with tag-method names */
struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */
TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */
} global_State;
lua_State(lstate.h#160)
/*
** 'per thread' state
*/
struct lua_State {
CommonHeader;
unsigned short nci; /* number of items in 'ci' list */
lu_byte status;
StkId top; /* first free slot in the stack */
global_State *l_G;
CallInfo *ci; /* call info for current function */
const Instruction *oldpc; /* last pc traced */
StkId stack_last; /* last free slot in the stack */
StkId stack; /* stack base */
UpVal *openupval; /* list of open upvalues in this stack */
GCObject *gclist;
struct lua_State *twups; /* list of threads with open upvalues */
struct lua_longjmp *errorJmp; /* current error recover point */
CallInfo base_ci; /* CallInfo for first level (C calling Lua) */
volatile lua_Hook hook;
ptrdiff_t errfunc; /* current error handling function (stack index) */
int stacksize;
int basehookcount;
int hookcount;
unsigned short nny; /* number of non-yieldable calls in stack */
unsigned short nCcalls; /* number of nested C calls */
l_signalT hookmask;
lu_byte allowhook;
};
CommonHeader(lobject.h#75)
/*
** 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
preinit_thread(lstate.c#217)
/*
** preinitialize a thread with consistent values without allocating
** any memory (to avoid errors)
*/
static void preinit_thread (lua_State *L, global_State *g) {
G(L) = g;
L->stack = NULL;
L->ci = NULL;
L->nci = 0;
L->stacksize = 0;
L->twups = L; /* thread has no upvalues */
L->errorJmp = NULL;
L->nCcalls = 0;
L->hook = NULL;
L->hookmask = 0;
L->basehookcount = 0;
L->allowhook = 1;
resethookcount(L); // #define resethookcount(L) (L->hookcount = L->basehookcount) # ldebug.h#18
L->openupval = NULL;
L->nny = 1;
L->status = LUA_OK;
L->errfunc = 0;
}
luaD_rawrunprotected(ldo.c#136)
int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
unsigned short oldnCcalls = L->nCcalls;
struct lua_longjmp lj;
lj.status = LUA_OK;
lj.previous = L->errorJmp; /* chain new error handler */
L->errorJmp = &lj;
LUAI_TRY(L, &lj,
(*f)(L, ud);
);
L->errorJmp = lj.previous; /* restore old error handler */
L->nCcalls = oldnCcalls;
return lj.status;
}
f_luaopen(lstate.c#198)
/*
** open parts of the state that may cause memory-allocation errors.
** ('g->version' != NULL flags that the state was completely build)
*/
static void f_luaopen (lua_State *L, void *ud) {
global_State *g = G(L);
UNUSED(ud);
stack_init(L, L); /* init stack */
init_registry(L, g);
luaS_init(L);
luaT_init(L);
luaX_init(L);
g->gcrunning = 1; /* allow gc */
g->version = lua_version(NULL);
luai_userstateopen(L);
}
lua_longjmp(ldo.c#84)
/* chain list of long jump buffers */
struct lua_longjmp {
struct lua_longjmp *previous;
luai_jmpbuf b;
volatile int status; /* error code */
};
LUAI_TRY(ldo.c#74)
#define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a }
stack_init(lstate.c#151)
static void stack_init (lua_State *L1, lua_State *L) {
int i; CallInfo *ci;
/* initialize stack array */
L1->stack = luaM_newvector(L, BASIC_STACK_SIZE, TValue);
L1->stacksize = BASIC_STACK_SIZE;
for (i = 0; i < BASIC_STACK_SIZE; i++)
setnilvalue(L1->stack + i); /* erase new stack */
L1->top = L1->stack;
L1->stack_last = L1->stack + L1->stacksize - EXTRA_STACK;
/* initialize first ci */
ci = &L1->base_ci;
ci->next = ci->previous = NULL;
ci->callstatus = 0;
ci->func = L1->top;
setnilvalue(L1->top++); /* 'function' entry for this 'ci' */
ci->top = L1->top + LUA_MINSTACK;
L1->ci = ci;
}
luaM_newvector(lmem.h#47)
#define luaM_newvector(L,n,t) \
cast(t *, luaM_reallocv(L, NULL, 0, n, sizeof(t)))
luaM_reallocv(lmem.h#17)
/*
** This macro reallocs a vector 'b' from 'on' to 'n' elements, where
** each element has size 'e'. In case of arithmetic overflow of the
** product 'n'*'e', it raises an error (calling 'luaM_toobig'). Because
** 'e' is always constant, it avoids the runtime division MAX_SIZET/(e).
**
** (The macro is somewhat complex to avoid warnings: The 'sizeof'
** comparison avoids a runtime comparison when overflow cannot occur.
** The compiler should be able to optimize the real test by itself, but
** when it does it, it may give a warning about "comparison is always
** false due to limited range of data type"; the +1 tricks the compiler,
** avoiding this warning but also this optimization.)
*/
#define luaM_reallocv(L,b,on,n,e) \
(((sizeof(n) >= sizeof(size_t) && cast(size_t, (n)) + 1 > MAX_SIZET/(e)) \
? luaM_toobig(L) : cast_void(0)) , \
luaM_realloc_(L, (b), (on)*(e), (n)*(e)))
luaM_realloc_(lmem.c#74)
/*
** generic allocation routine.
*/
void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
void *newblock;
global_State *g = G(L);
size_t realosize = (block) ? osize : 0;
lua_assert((realosize == 0) == (block == NULL));
#if defined(HARDMEMTESTS)
if (nsize > realosize && g->gcrunning)
luaC_fullgc(L, 1); /* force a GC whenever possible */
#endif
newblock = (*g->frealloc)(g->ud, block, osize, nsize);
if (newblock == NULL && nsize > 0) {
lua_assert(nsize > realosize); /* cannot fail when shrinking a block */
if (g->version) { /* is state fully built? */
luaC_fullgc(L, 1); /* try to free some memory... */
newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */
}
if (newblock == NULL)
luaD_throw(L, LUA_ERRMEM);
}
lua_assert((nsize == 0) == (newblock == NULL));
g->GCdebt = (g->GCdebt + nsize) - realosize;
return newblock;
}
CallInfo(lstate.h#65)
/*
** Information about a call.
** When a thread yields, 'func' is adjusted to pretend that the
** top function has only the yielded values in its stack; in that
** case, the actual 'func' value is saved in field 'extra'.
** When a function calls another with a continuation, 'extra' keeps
** the function index so that, in case of errors, the continuation
** function can be called with the correct top.
*/
typedef struct CallInfo {
StkId func; /* function index in the stack */
StkId top; /* top for this function */
struct CallInfo *previous, *next; /* dynamic call link */
union {
struct { /* only for Lua functions */
StkId base; /* base for this function */
const Instruction *savedpc;
} l;
struct { /* only for C functions */
lua_KFunction k; /* continuation in case of yields */
ptrdiff_t old_errfunc;
lua_KContext ctx; /* context info. in case of yields */
} c;
} u;
ptrdiff_t extra;
short nresults; /* expected number of results from this function */
unsigned short callstatus;
} CallInfo;
init_registry(lstate.c#181)
/*
** Create registry table and its predefined values
*/
static void init_registry (lua_State *L, global_State *g) {
TValue temp;
/* create registry */
Table *registry = luaH_new(L);
sethvalue(L, &g->l_registry, registry);
luaH_resize(L, registry, LUA_RIDX_LAST, 0);
/* registry[LUA_RIDX_MAINTHREAD] = L */
setthvalue(L, &temp, L); /* temp = L */
luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &temp);
/* registry[LUA_RIDX_GLOBALS] = table of globals */
sethvalue(L, &temp, luaH_new(L)); /* temp = new table (global table) */
luaH_setint(L, registry, LUA_RIDX_GLOBALS, &temp);
}
luaH_new(ltable.c#402)
Table *luaH_new (lua_State *L) {
GCObject *o = luaC_newobj(L, LUA_TTABLE, sizeof(Table));
Table *t = gco2t(o);
t->metatable = NULL;
t->flags = cast_byte(~0);
t->array = NULL;
t->sizearray = 0;
setnodevector(L, t, 0);
return t;
}
luaC_newobj(lgc.c#204)
/*
** create a new collectable object (with given type and size) and link
** it to 'allgc' list.
*/
GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
global_State *g = G(L);
GCObject *o = cast(GCObject *, luaM_newobject(L, novariant(tt), sz));
o->marked = luaC_white(g);
o->tt = tt;
o->next = g->allgc;
g->allgc = o;
return o;
}
luaM_newobject(lmem.h#50)
#define luaM_newobject(L,tag,s) luaM_realloc_(L, NULL, tag, (s))
GCObject(lobject.h#82)
/*
** Common type has only the common header
*/
struct GCObject {
CommonHeader;
};
gco2t(lstate.h#214)
#define gco2t(o) check_exp((o)->tt == LUA_TTABLE, &((cast_u(o))->h))
cast_u(lstate.h#204)
#define cast_u(o) cast(union GCUnion *, (o))
GCUnion(lstate.h#190)
/*
** Union of all collectable objects (only for conversions)
*/
union GCUnion {
GCObject gc; /* common header */
struct TString ts;
struct Udata u;
union Closure cl;
struct Table h;
struct Proto p;
struct lua_State th; /* thread */
};
Table(lobjec.h#497)
typedef struct Table {
CommonHeader;
lu_byte flags; /* 1<<p means tagmethod(p) is not present */
lu_byte lsizenode; /* log2 of size of 'node' array */
unsigned int sizearray; /* size of 'array' array */
TValue *array; /* array part */
Node *node;
Node *lastfree; /* any free position is before this position */
struct Table *metatable;
GCObject *gclist;
} Table;
sethvalue(lobject.h#250)
#define sethvalue(L,obj,x) \
{ TValue *io = (obj); Table *x_ = (x); \
val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTABLE)); \
checkliveness(L,io); }
luaH_resize(ltable.c#333)
void luaH_resize (lua_State *L, Table *t, unsigned int nasize,
unsigned int nhsize) {
unsigned int i;
int j;
unsigned int oldasize = t->sizearray;
int oldhsize = allocsizenode(t);
Node *nold = t->node; /* save old hash ... */
if (nasize > oldasize) /* array part must grow? */
setarrayvector(L, t, nasize);
/* create new hash part with appropriate size */
setnodevector(L, t, nhsize);
if (nasize < oldasize) { /* array part must shrink? */
t->sizearray = nasize;
/* re-insert elements from vanishing slice */
for (i=nasize; i<oldasize; i++) {
if (!ttisnil(&t->array[i]))
luaH_setint(L, t, i + 1, &t->array[i]);
}
/* shrink array */
luaM_reallocvector(L, t->array, oldasize, nasize, TValue);
}
/* re-insert elements from hash part */
for (j = oldhsize - 1; j >= 0; j--) {
Node *old = nold + j;
if (!ttisnil(gval(old))) {
/* doesn't need barrier/invalidate cache, as entry was
already present in the table */
setobjt2t(L, luaH_set(L, t, gkey(old)), gval(old));
}
}
if (oldhsize > 0) /* not the dummy node? */
luaM_freearray(L, nold, cast(size_t, oldhsize)); /* free old hash */
}
luaS_init(lstring.c#113)
/*
** Initialize the string table and the string cache
*/
void luaS_init (lua_State *L) {
global_State *g = G(L);
int i, j;
luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */
/* pre-create memory-error message */
g->memerrmsg = luaS_newliteral(L, MEMERRMSG);
luaC_fix(L, obj2gco(g->memerrmsg)); /* it should never be collected */
for (i = 0; i < STRCACHE_N; i++) /* fill cache with valid strings */
for (j = 0; j < STRCACHE_M; j++)
g->strcache[i][j] = g->memerrmsg;
}
luaT_init(ltm.c#37)
void luaT_init (lua_State *L) {
static const char *const luaT_eventname[] = { /* ORDER TM */
"__index", "__newindex",
"__gc", "__mode", "__len", "__eq",
"__add", "__sub", "__mul", "__mod", "__pow",
"__div", "__idiv",
"__band", "__bor", "__bxor", "__shl", "__shr",
"__unm", "__bnot", "__lt", "__le",
"__concat", "__call"
};
int i;
for (i=0; i<TM_N; i++) {
G(L)->tmname[i] = luaS_new(L, luaT_eventname[i]);
luaC_fix(L, obj2gco(G(L)->tmname[i])); /* never collect these names */
}
}
luaX_init(llex.c#70)
void luaX_init (lua_State *L) {
int i;
TString *e = luaS_newliteral(L, LUA_ENV); /* create env name */
luaC_fix(L, obj2gco(e)); /* never collect this name */
for (i=0; i<NUM_RESERVED; i++) {
TString *ts = luaS_new(L, luaX_tokens[i]);
luaC_fix(L, obj2gco(ts)); /* reserved words are never collected */
ts->extra = cast_byte(i+1); /* reserved word */
}
}
lua_version(lapi.c#144)
LUA_API const lua_Number *lua_version (lua_State *L) {
static const lua_Number version = LUA_VERSION_NUM;
if (L == NULL) return &version;
else return G(L)->version;
}
luai_userstateopen(llimits.h#227)
/*
** these macros allow user-specific actions on threads when you defined
** LUAI_EXTRASPACE and need to do something extra when a thread is
** created/deleted/resumed/yielded.
*/
#if !defined(luai_userstateopen)
#define luai_userstateopen(L) ((void)L)
#endif
lua_atpanic(lapi.c#134)
LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf) {
lua_CFunction old;
lua_lock(L);
old = G(L)->panic;
G(L)->panic = panicf;
lua_unlock(L);
return old;
}
panic(lauxlib.c#1019)
static int panic (lua_State *L) {
lua_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n",
lua_tostring(L, -1));
return 0; /* return to Lua to abort */
}
lua_pushcfunction(lua.h#350)
#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0)
lua_pushcclosure(lapi.c#532)
LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
lua_lock(L);
if (n == 0) {
setfvalue(L->top, fn);
}
else {
CClosure *cl;
api_checknelems(L, n);
api_check(L, n <= MAXUPVAL, "upvalue index too large");
cl = luaF_newCclosure(L, n);
cl->f = fn;
L->top -= n;
while (n--) {
setobj2n(L, &cl->upvalue[n], L->top + n);
/* does not need barrier because closure is white */
}
setclCvalue(L, L->top, cl);
}
api_incr_top(L);
luaC_checkGC(L);
lua_unlock(L);
}
api_incr_top(lapi.h#14)
#define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \
"stack overflow");}
luaC_checkGC(lgc.h#114)
/* more often than not, 'pre'/'pos' are empty */
#define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0)
luaC_condGC(lgc.h#104)
/*
** Does one step of collection when debt becomes positive. 'pre'/'pos'
** allows some adjustments to be done only when needed. macro
** 'condchangemem' is used only for heavy tests (forcing a full
** GC cycle on every opportunity)
*/
#define luaC_condGC(L,pre,pos) \
{ if (G(L)->GCdebt > 0) { pre; luaC_step(L); pos;}; \
condchangemem(L,pre,pos); }
luaC_step(lgc.c#1125)
/*
** performs a basic GC step when collector is running
*/
void luaC_step (lua_State *L) {
global_State *g = G(L);
l_mem debt = getdebt(g); /* GC deficit (be paid now) */
if (!g->gcrunning) { /* not running? */
luaE_setdebt(g, -GCSTEPSIZE * 10); /* avoid being called too often */
return;
}
do { /* repeat until pause or enough "credit" (negative debt) */
lu_mem work = singlestep(L); /* perform one single step */
debt -= work;
} while (debt > -GCSTEPSIZE && g->gcstate != GCSpause);
if (g->gcstate == GCSpause)
setpause(g); /* pause until next cycle */
else {
debt = (debt / g->gcstepmul) * STEPMULADJ; /* convert 'work units' to Kb */
luaE_setdebt(g, debt);
runafewfinalizers(L);
}
}
lua_pushinteger(lapi.c#466)
LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) {
lua_lock(L);
setivalue(L->top, n);
api_incr_top(L);
lua_unlock(L);
}
lua_pushlightuserdata(lapi.c#564)
LUA_API void lua_pushlightuserdata (lua_State *L, void *p) {
lua_lock(L);
setpvalue(L->top, p);
api_incr_top(L);
lua_unlock(L);
}
lua_pcall(lua.h#278)
#define lua_pcall(L,n,r,f) lua_pcallk(L, (n), (r), (f), 0, NULL)
lua_pcallk(lapi.c#947)
LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc,
lua_KContext ctx, lua_KFunction k) {
struct CallS c;
int status;
ptrdiff_t func;
lua_lock(L);
api_check(L, k == NULL || !isLua(L->ci),
"cannot use continuations inside hooks");
api_checknelems(L, nargs+1);
api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread");
checkresults(L, nargs, nresults);
if (errfunc == 0)
func = 0;
else {
StkId o = index2addr(L, errfunc);
api_checkstackindex(L, errfunc, o);
func = savestack(L, o);
}
c.func = L->top - (nargs+1); /* function to be called */
if (k == NULL || L->nny > 0) { /* no continuation or no yieldable? */
c.nresults = nresults; /* do a 'conventional' protected call */
status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func);
}
else { /* prepare continuation (call is already protected by 'resume') */
CallInfo *ci = L->ci;
ci->u.c.k = k; /* save continuation */
ci->u.c.ctx = ctx; /* save context */
/* save information for error recovery */
ci->extra = savestack(L, c.func);
ci->u.c.old_errfunc = L->errfunc;
L->errfunc = func;
setoah(ci->callstatus, L->allowhook); /* save value of 'allowhook' */
ci->callstatus |= CIST_YPCALL; /* function can do error recovery */
luaD_call(L, c.func, nresults); /* do the call */
ci->callstatus &= ~CIST_YPCALL;
L->errfunc = ci->u.c.old_errfunc;
status = LUA_OK; /* if it is here, there were no errors */
}
adjustresults(L, nresults);
lua_unlock(L);
return status;
}
api_checknelems(lapi.h#20)
#define api_checknelems(L,n) api_check(L, (n) < (L->top - L->ci->func), \
"not enough elements in the stack")
luaD_pcall(ldo.c#721)
int luaD_pcall (lua_State *L, Pfunc func, void *u,
ptrdiff_t old_top, ptrdiff_t ef) {
int status;
CallInfo *old_ci = L->ci;
lu_byte old_allowhooks = L->allowhook;
unsigned short old_nny = L->nny;
ptrdiff_t old_errfunc = L->errfunc;
L->errfunc = ef;
status = luaD_rawrunprotected(L, func, u);
if (status != LUA_OK) { /* an error occurred? */
StkId oldtop = restorestack(L, old_top);
luaF_close(L, oldtop); /* close possible pending closures */
seterrorobj(L, status, oldtop);
L->ci = old_ci;
L->allowhook = old_allowhooks;
L->nny = old_nny;
luaD_shrinkstack(L);
}
L->errfunc = old_errfunc;
return status;
}
pmain(lua.c#550)
/*
** Main body of stand-alone interpreter (to be called in protected mode).
** Reads the options and handles them all.
*/
static int pmain (lua_State *L) {
int argc = (int)lua_tointeger(L, 1);
char **argv = (char **)lua_touserdata(L, 2);
int script;
int args = collectargs(argv, &script);
luaL_checkversion(L); /* check that interpreter has correct version */
if (argv[0] && argv[0][0]) progname = argv[0];
if (args == has_error) { /* bad arg? */
print_usage(argv[script]); /* 'script' has index of bad arg. */
return 0;
}
if (args & has_v) /* option '-v'? */
print_version();
if (args & has_E) { /* option '-E'? */
lua_pushboolean(L, 1); /* signal for libraries to ignore env. vars. */
lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
}
luaL_openlibs(L); /* open standard libraries */
createargtable(L, argv, argc, script); /* create table 'arg' */
if (!(args & has_E)) { /* no option '-E'? */
if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */
return 0; /* error running LUA_INIT */
}
if (!runargs(L, argv, script)) /* execute arguments -e and -l */
return 0; /* something failed */
if (script < argc && /* execute main script (if there is one) */
handle_script(L, argv + script) != LUA_OK)
return 0;
if (args & has_i) /* -i option? */
doREPL(L); /* do read-eval-print loop */
else if (script == argc && !(args & (has_e | has_v))) { /* no arguments? */
if (lua_stdin_is_tty()) { /* running in interactive mode? */
print_version();
doREPL(L); /* do read-eval-print loop */
}
else dofile(L, NULL); /* executes stdin as a file */
}
lua_pushboolean(L, 1); /* signal no errors */
return 1;
}