Lua execution flow
Lua version 5.3.5.
# ----- lua.c--main (6NJXA) -----
# Main function.
#
int main (int argc, char **argv)
# Create `lua_State` and `global_State`.
lauxlib.c--luaL_newstate...(3OEVI)
# Push function `pmain` to stack.
lua.h--lua_pushcfunction
# Push `argc` to stack.
lapi.c--lua_pushinteger
# Push `argv` to stack.
lapi.c--lua_pushlightuserdata
# Call function `pmain` on stack.
lua.h--lua_pcall...(3GERF)
lapi.c--lua_pcallk...(6YGT0)
ldo.c--luaD_pcall...(3RVKZ)
ldo.c--luaD_rawrunprotected...(2LSGL)
ldo.c--LUAI_TRY...(6GUZS)
ldo.c--luaD_callnoyield...(5SH0J)
ldo.c--luaD_call...(60ZE7)
lua.c--pmain...(5MWJ5)
# Close `lua_State`.
lstate.c--lua_close
# ----- lauxlib.c--luaL_newstate (3OEVI) -----
# Create `lua_State` and `global_State`.
#
lauxlib.c--luaL_newstate
# Create a `LG` object containing a `lua_State` and a `global_State`.
lstate.c--lua_newstate
# Initialize `lua_State` fields.
lstate.c--preinit_thread
```
L->errorJmp = NULL;
L->nCcalls = 0;
```
# Call `lstate.c--f_luaopen`.
ldo.c--luaD_rawrunprotected...(2LSGL)
# Initialize the lua_State.
lstate.c--f_luaopen
# Initialize `lua_State->stack` and `lua_State->stacksize`.
lstate.c--stack_init
```
L1->stack = luaM_newvector(L, BASIC_STACK_SIZE, TValue);
L1->stacksize = BASIC_STACK_SIZE;
```
# Initialize `lua_State->stack_last`
```
L1->stack_last = L1->stack + L1->stacksize - EXTRA_STACK;
```
# Initialize `lua_State->ci`
```
ci->func = L1->top;
setnilvalue(L1->top++);
ci->top = L1->top + LUA_MINSTACK;
```
# Use `lua_State->base_ci` as `lua_State->ci`.
```
ci = &L1->base_ci;
L1->ci = ci;
```
# Initialize the lua_State's registry table.
lstate.c--init_registry
ltable.c--luaH_new
ltable.c--luaH_resize
ltable.c--luaH_setint
```
luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &temp);
luaH_setint(L, registry, LUA_RIDX_GLOBALS, &temp);
```
# Initialize the lua_State's string table and string cache.
lstring.c--luaS_init
# Resize the lua_State's string table to initial size 128.
lstring.c--luaS_resize
# Initialize the lua_State's tagged method names array.
lstring.c--luaT_init
# Create reserved words strings in cache.
llex.c--luaX_init
# Turn on GC status.
```
g->gcrunning = 1;
```
# Set panic function.
lapi.c--lua_atpanic
# ----- lua.c--pmain (5MWJ5) -----
static int pmain (lua_State *L)
lua.c--collectargs
// Open standard libraries.
linit.c--luaL_openlibs
lua.c--createargtable
lapi.c--lua_createtable
// 25GPR
// Set global value `arg`.
lua.c--handle_script...(2MJMK)
# ----- lua.c--handle_script (2MJMK) -----
# Compile source code file to Lua entry function.
# Push Lua entry function to stack.
# Push command line arguments to stack.
# Call Lua entry function on stack, using `msghandler` as error function.
#
static int handle_script (lua_State *L, char **argv)
// Compile source code file to Lua entry function.
// Push Lua entry function to stack.
lauxlib.h--luaL_loadfile...(5612R)
// Push command line arguments to stack.
lua.c--pushargs
// Call Lua entry function on stack, using `msghandler` as error function.
lua.c--docall...(5BEQA)
# ----- lauxlib.h--luaL_loadfile (5612R) -----
# Compile source code file to Lua entry function.
#
lauxlib.h--luaL_loadfile
lauxlib.c--luaL_loadfilex
lapi.c--lua_load
ldo.c--luaD_protectedparser
ldo.c--luaD_pcall...(3RVKZ)
ldo.c--luaD_rawrunprotected...(2LSGL)
ldo.c--f_parser...(2OAT3)
# At this point, the Lua entry function is in stack slot `L->top - 1`.
# Set globals table as the first upvalue of the entry function.
# ----- lua.c--docall (5BEQA) -----
# Call target function on stack, using `msghandler` as error function.
#
static int docall (lua_State *L, int narg, int nres)
int status;
int base = lua_gettop(L) - narg; /* function index */
// 24ATD
// Insert `msghandler` before the target functon.
// Use `msghandler` as error function.
lua_pushcfunction(L, msghandler); /* push message handler */
lua_insert(L, base); /* put it under function and args */
globalL = L; /* to be available to 'laction' */
// Register signal handler for SIGINT.
signal(SIGINT, laction); /* set C-signal handler */
// Call `lua_pcall` to call target function on stack.
// lua.h--lua_pcall...(3GERF)
status = lua_pcall(L, narg, nres, base);
// Restore signal handler for SIGINT.
signal(SIGINT, SIG_DFL); /* reset C-signal handler */
lua_remove(L, base); /* remove message handler from the stack */
// Return call status.
return status;
# ----- lbaselib.c--luaB_dofile (3XBIZ) -----
# Compile source code file to Lua entry function.
# Push Lua entry function to stack.
# Call Lua entry function on stack.
#
static int luaB_dofile (lua_State *L) {
const char *fname = luaL_optstring(L, 1, NULL);
lua_settop(L, 1);
// Compile source code file to Lua entry function.
// Push Lua entry function to stack.
// lauxlib.h--luaL_loadfile...(5612R)
if (luaL_loadfile(L, fname) != LUA_OK)
return lua_error(L);
// Call Lua entry function on stack.
// lapi.c--lua_callk...(6OHLR)
lua_callk(L, 0, LUA_MULTRET, 0, dofilecont);
return dofilecont(L, 0, 0);
}
# ----- lbaselib.c--luaB_pcall (5QUOY) -----
# Call target function with error recovery.
#
static int luaB_pcall (lua_State *L) {
// Stack: ... | target_func | target_func_args | top
int status;
luaL_checkany(L, 1);
// Push the first on-stack result `true`.
// Stack: ... | target_func | target_func_args | true | top
lua_pushboolean(L, 1); /* first result if no errors */
// Move the first result `true` below the target function's arguments.
// Stack: ... | true | target_func | target_func_args | top
lua_insert(L, 1); /* put it in place */
// 6KTFG
// lapi.c--lua_pcallk...(6YGT0)
// Arg 1: lua_State.
// Arg 2: Number of arguments passed to the target function.
// `lua_pcallk` uses the last `nargs` arguments near stack top.
// `- 2` excludes the first result `true` and the target function.
// Arg 3: Number of results wanted by the calling context.
// Arg 4: Error function's stack slot index. 0 is special for nil.
// Arg 5: Continuation function argument.
// Arg 6: Continuation function, called during coroutine unrolling in 3HYNI.
status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 0, 0, finishpcall);
// lbaselib.c--finishpcall...(7XIVE)
return finishpcall(L, status, 0);
}
# ----- lbaselib.c--luaB_xpcall (3GVJZ) -----
# Call target function with error recovery and custom error function.
#
static int luaB_xpcall (lua_State *L) {
// Stack: ... | target_func | error_func | target_func_args | top
int status;
int n = lua_gettop(L);
luaL_checktype(L, 2, LUA_TFUNCTION); /* check error function */
// Push the first result `true`.
// Stack: ... | target_func | error_func | target_func_args | true | top
lua_pushboolean(L, 1); /* first result */
// Push the called function.
// Stack: ... | target_func | error_func | target_func_args | true
| target_func | top
lua_pushvalue(L, 1); /* function */
// Move the first result `true` and the called function below the called
// function's arguments.
// Stack: ... | target_func | error_func | true | target_func
| target_func_args | top
lua_rotate(L, 3, 2); /* move them below function's arguments */
// 2AAB2
// lapi.c--lua_pcallk...(6YGT0)
// Arg 1: lua_State.
// Arg 2: Number of arguments passed to the target function.
// `lua_pcallk` uses the last `nargs` arguments near the top.
// `- 2` excludes the called function and the message handler.
// Arg 3: Number of results wanted by the calling context.
// Arg 4: Error function's slot index. 0 is special for nil.
// Arg 5: Continuation function argument.
// Arg 6: Continuation function, called during coroutine unrolling in 3HYNI.
status = lua_pcallk(L, n - 2, LUA_MULTRET, 2, 2, finishpcall);
// lbaselib.c--finishpcall...(7XIVE)
return finishpcall(L, status, 2);
}
# ----- lbaselib.c--finishpcall (7XIVE) -----
# Continuation function for 'pcall' and 'xpcall'.
#
static int finishpcall (lua_State *L, int status, lua_KContext extra) {
if (status != LUA_OK && status != LUA_YIELD) { /* error? */
lua_pushboolean(L, 0); /* first result (false) */
lua_pushvalue(L, -2); /* error message */
return 2; /* return false, msg */
}
else
// Lua-level C function pushes n results to stack,
// stored in `L->top - n` to `L->top - 1`.
// Lua-level C function returns the number of on-stack results.
return lua_gettop(L) - (int)extra; /* return all results */
}
# ----- lua.h--lua_pcall (3GERF) -----
# Macro for `lua_pcallk`.
# Continuation function argument `ctx` be 0.
# Continuation function `k` be NULL.
#
```
// lapi.c--lua_pcallk...(6YGT0)
#define lua_pcall(L,n,r,f) lua_pcallk(L, (n), (r), (f), 0, NULL)
```
# ----- lapi.c--lua_pcallk (6YGT0) -----
# Call target function on stack.
# The target function and its arguments are expected to be pushed on stack.
# They are located according to the arguments count `nargs`.
#
LUA_API int lua_pcallk (
lua_State *L,
int nargs,
int nresults,
int errfunc,
lua_KContext ctx,
lua_KFunction k
)
// L: lua_State.
//
// nargs: Number of arguments passed to the target function.
// The target function should be on `L->top - (nargs+1)`.
// The arguments for the target function should be on
// (L->top - nargs) to (L->top - 1).
//
// nresults: Number of results wanted by the calling context.
//
// errfunc: Error function's slot index. 0 is special for nil.
// Argument for `f_call`.
// The struct contains target function stack slot pointer, and the number of
// results wanted by the calling context.
struct CallS c;
// Call status.
int status;
// Bytes offset from stack bottom to the error function.
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");
// Ensure results do not overflow stack.
checkresults(L, nargs, nresults);
// If error function's stack slot index is 0.
if (errfunc == 0)
// Point `func` to stack bottom `L->stack`.
// At 7R4LM, the slot on L->stack is set to be nil.
func = 0;
else {
// Get error function's stack slot pointer
StkId o = index2addr(L, errfunc);
api_checkstackindex(L, errfunc, o);
// Point `func` to the error function.
func = savestack(L, o);
}
// Store target function's stack slot pointer in `CallS.func`.
c.func = L->top - (nargs+1); /* function to be called */
// If have no continuation function or is not yieldable, use
// `luaD_pcall` and `f_call` to call the target function.
//
// `f_call` calls `luaD_callnoyield`, which increments `L->nyy`.
// `L->nny > 0` forbids yields in `lua_yieldk` at 63IHL.
// The purpose to forbid yields is to ensure all the Lua-level C functions
// found during coroutine unrolling have continuation function at 5VO87.
//
if (k == NULL || L->nny > 0) { /* no continuation or no yieldable? */
// Store number of results wanted by calling context in `CallS.nresults`.
c.nresults = nresults; /* do a 'conventional' protected call */
// 631AI
// ldo.c--luaD_pcall...(3RVKZ)
// Call `luaD_pcall` to call `f_call`.
// Arg 1: lua_State.
// Arg 2: `f_call`, which in turn calls the target function.
// Arg 3: Userdata pointer passed as argument when calling `f_call`.
// Arg 4: The old stack top (byte offset from stack bottom) to restore when
// the call has error.
// Arg 5: The error function's stack slot's byte offset from stack bottom.
//
status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func);
}
else { /* prepare continuation (call is already protected by 'resume') */
// 33NSM
// Get calling context's call info.
CallInfo *ci = L->ci;
// Store continuation function in the calling context's call info.
ci->u.c.k = k; /* save continuation */
// Store continuation function argument in the calling context's call info.
ci->u.c.ctx = ctx; /* save context */
// 3T2MK
// Store target function's stack slot's bytes offset.
// Used by error recovery at 7ZDHI.
/* save information for error recovery */
ci->extra = savestack(L, c.func);
// 5I0AI
// Store old error function.
ci->u.c.old_errfunc = L->errfunc;
L->errfunc = func;
setoah(ci->callstatus, L->allowhook); /* save value of 'allowhook' */
// 2JIO8
// Indicate it is a protected call with continuation function for error
// recovery.
ci->callstatus |= CIST_YPCALL; /* function can do error recovery */
// ldo.c--luaD_call...(60ZE7)
// Call `luaD_call` to call target function.
luaD_call(L, c.func, nresults); /* do the call */
ci->callstatus &= ~CIST_YPCALL;
// Restore old error function.
// `ci->u.c.old_errfunc` is set at 5I0AI.
L->errfunc = ci->u.c.old_errfunc;
status = LUA_OK; /* if it is here, there were no errors */
}
// lapi.h--adjustresults...(3RQ2D)
// If the number of results wanted is unfixed, and the call info's frame top
// < the stack top, set the call info's frame top to be equal to the stack
// top.
adjustresults(L, nresults);
lua_unlock(L);
// Return call status.
return status;
# ----- lapi.c--lua_call (5BUBM) -----
# Macro for `lua_callk`.
# Continuation function argument `ctx` be 0.
# Continuation function `k` be NULL.
#
```
#define lua_call(L,n,r) lua_callk(L, (n), (r), 0, NULL)
```
# ----- lapi.c--lua_callk (6OHLR) -----
LUA_API void lua_callk (
lua_State *L,
int nargs,
int nresults,
lua_KContext ctx,
lua_KFunction k
)
StkId 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);
// Get the target function's slot pointer.
func = L->top - (nargs+1);
// If have continuation function and is yieldable.
if (k != NULL && L->nny == 0) { /* need to prepare continuation? */
// Store continuation function.
L->ci->u.c.k = k; /* save continuation */
// Store continuation function argument.
L->ci->u.c.ctx = ctx; /* save context */
// Call the target function.
// ldo.c--luaD_call...(60ZE7)
luaD_call(L, func, nresults); /* do the call */
}
else /* no continuation or no yieldable */
// Call the target function, incrementing `L->nyy` to forbid yields.
// ldo.c--luaD_callnoyield...(5SH0J)
luaD_callnoyield(L, func, nresults); /* just do the call */
// lapi.h--adjustresults...(3RQ2D)
// If the number of results wanted is unfixed, and the call info's frame top
// < the stack top, set the call info's frame top to be equal to the stack
// top.
adjustresults(L, nresults);
lua_unlock(L);
# ----- ldo.c--luaD_pcall (3RVKZ) -----
# Store `L->ci`, `L->allowhook`, `L->nny`, `L->errfunc`.
# Call `luaD_rawrunprotected` to call target function.
# If the status returned by `luaD_rawrunprotected` is not LUA_OK, restore
# `L->ci`, `L->allowhook`, `L->nny`, and call `seterrorobj` to set error
# message to old stack top.
# Restore `L->errfunc`.
#
ldo.c--luaD_pcall(
lua_State *L,
Pfunc func,
void *u,
ptrdiff_t old_top,
ptrdiff_t ef
)
// L: lua_State.
//
// func: Target function pointer.
//
// u: Target function argument.
//
// old_top: Old stack top's stack slot's byte offset from stack bottom.
//
// ef: The error function's stack slot's byte offset from stack bottom.
// Store old call info.
CallInfo *old_ci = L->ci;
// Store old `allowhook`
lu_byte old_allowhooks = L->allowhook;
// Store old number of non-yieldable calls.
unsigned short old_nny = L->nny;
// Store old error function's stack byte offset.
ptrdiff_t old_errfunc = L->errfunc;
// Set new error function's stack byte offset.
L->errfunc = ef;
// Call `luaD_rawrunprotected` to call target function with given target
// function argument.
ldo.c--luaD_rawrunprotected...(2LSGL)
```
status = luaD_rawrunprotected(L, func, u);c
```
if (status != LUA_OK) { /* an error occurred? */
// Get old stack top pointer.
StkId oldtop = restorestack(L, old_top);
// Close open upvalues.
luaF_close(L, oldtop);
// Restore the old stack top.
// Push error message to stack.
// The error message is pushed to stack before calling LUAI_THROW at 3GFYH.
seterrorobj(L, status, oldtop);
// Restore old call info.
L->ci = old_ci;
// Restore old `allowhook`
L->allowhook = old_allowhooks;
// Restore old number of non-yieldable calls.
L->nny = old_nny;
// Shrink stack.
ldo.c--luaD_shrinkstack
// Restore old error function's stack byte offset.
L->errfunc = old_errfunc;
// Return call status.
return status;
# ----- ldo.c--luaD_rawrunprotected (2LSGL) -----
# Store `L->nCcalls`, `L->errorJmp`.
# Point `L->errorJmp` to a new lua_longjmp struct so that `LUAI_TRY`'s setjmp
# stores context info in this struct, not overwriting the old one.
# Call target function.
# Restore `L->nCcalls`, `L->errorJmp`.
# Return the status code in `L->errorJmp.status`.
#
int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
// Store old number of nexted C calls
unsigned short oldnCcalls = L->nCcalls;
// Create new error jump info.
struct lua_longjmp lj;
// Set initial call status.
lj.status = LUA_OK;
// Save old error jump info.
lj.previous = L->errorJmp; /* chain new error handler */
// Set new error jump info.
L->errorJmp = &lj;
// 7KZPY
// Save execution context to `L->errorJmp->b` and call target function.
// ldo.c--LUAI_TRY...(6GUZS)
LUAI_TRY(L, &lj,
(*f)(L, ud);
);
// Restore old error jump info.
L->errorJmp = lj.previous; /* restore old error handler */
// Restore old number of nexted C calls.
L->nCcalls = oldnCcalls;
// Return call status.
// `lj.status` is set by luaD_throw at 1VSQU.
return lj.status;
}
# ----- ldo.c--LUAI_TRY (6GUZS) -----
# Save execution context to `L->errorJmp->b` and call target function.
#
# `LUAI_TRY` calls `setjmp` to save current execution context to
# `L->errorJmp->b`, so that in case of error, execution can jump back at 3GFYH
# by restoring context in `L->errorJmp->b`.
#
```
#define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a }
```
# ----- lapi.c--f_call (2FMDX) -----
# Call `luaD_callnoyield` to call target function.
#
# `f_call` is simply an indirection for `luaD_callnoyield` in order to adapt to
# `luaD_rawrunprotected`'s interface.
#
static void f_call (lua_State *L, void *ud)
struct CallS *c = cast(struct CallS *, ud);
// ldo.c--luaD_callnoyield...(5SH0J)
luaD_callnoyield(L, c->func, c->nresults);
# ----- ldo.c--luaD_callnoyield (5SH0J) -----
# Increase `L->nny`.
# Call `luaD_call`.
# Decrease `L->nny`.
#
void luaD_callnoyield (lua_State *L, StkId func, int nResults)
L->nny++;
// ldo.c--luaD_call...(60ZE7)
luaD_call(L, func, nResults);
L->nny--;
# ----- ldo.c--luaD_call (60ZE7) -----
# Increment `L->nCcalls`.
# Call `luaD_precall`.
# Call `luaV_execute` if `func` is a Lua function.
# Decrement `L->nCcalls`.
#
void luaD_call (lua_State *L, StkId func, int nResults)
// Increment number of nested C calls.
// If the number is GE max limit.
if (++L->nCcalls >= LUAI_MAXCCALLS)
stackerror(L);
// ldo.c--luaD_precall...(7KDMP)
if (!luaD_precall(L, func, nResults)) /* is a Lua function? */
// lvm.c--luaV_execute...(3UH1T)
luaV_execute(L); /* call it */
// Decrement number of nested C calls.
L->nCcalls--;
# ----- ldo.c--luaD_precall (7KDMP) -----
# Create call info and point `L->ci` to it.
# If the target function is Lua-level C function, call it, and then
# call `luaD_poscall` to move results and restore to previous call info.
# If the target function is a Lua function, leave it to `luaV_execute`.
#
int luaD_precall (lua_State *L, StkId func, int nresults)
lua_CFunction f;
CallInfo *ci;
switch (ttype(func)) {
case LUA_TCCL: /* C closure */
f = clCvalue(func)->f;
goto Cfunc;
case LUA_TLCF: /* light C function */
f = fvalue(func);
Cfunc: {
int n; /* number of returns */
// Ensure stack slots are enough.
checkstackp(L, LUA_MINSTACK, func); /* ensure minimum stack size */
// Create new call info and point `ci` and `L->ci` to it.
ci = next_ci(L); /* now 'enter' new function */
// 2Y2MD
// Store the number of results wanted by the calling context.
ci->nresults = nresults;
// Store the target function's stack slot pointer.
ci->func = func;
// 2A3I0
// Point `ci->top` to right after the target function's stack frame.
// Because it is a Lua-level C function, its Lua stack frame size is not
// known by compiler, so it is assumed to be `LUA_MINSTACK`. Slots
// between [L->top, L->top + LUA_MINSTACK) are reserved for all Lua-level
// variables the C function uses.
//
// `L->top` is set at 3NSCL to point to right after the arguments
// passed.
//
ci->top = L->top + LUA_MINSTACK;
lua_assert(ci->top <= L->stack_last);
ci->callstatus = 0;
if (L->hookmask & LUA_MASKCALL)
luaD_hook(L, LUA_HOOKCALL, -1);
lua_unlock(L);
// Lua-level C function is called directly because no Lua opcodes
// execution is needed.
//
// Lua-level C function does not need offset base bacause arguments and
// local variables access are not encoded in Lua opcodes.
//
// Lua-level C function pushes Lua-level results to stack, stored in
// `L->top - n` to `L->top - 1`.
//
// Lua-level C function returns the number of on-stack results.
//
n = (*f)(L); /* do the actual call */
lua_lock(L);
api_checknelems(L, n);
// ldo.c--luaD_poscall...(2V8KP)
// Restore previous call info.
// Move results to slots starting from the target function's slot
// `L->func`.
// Adjust `L->top` to point to right after the results wanted.
luaD_poscall(L, ci, L->top - n, n);
// Indicate it is a Lua-level C function.
return 1;
}
case LUA_TLCL: { /* Lua function: prepare its call */
StkId base;
// Get the target function's prototype.
Proto *p = clLvalue(func)->p;
// 5NTGX
// Get the number of arguments passed to the target function.
int n = cast_int(L->top - func) - 1; /* number of real arguments */
// Get the target function's frame size.
int fsize = p->maxstacksize; /* frame size */
// Ensure stack slots are enough.
checkstackp(L, fsize, func);
// If the target function takes unfixed arguments.
if (p->is_vararg)
// Move fixed arguments to slots after unfixed arguments.
// Set the offset base to point to the first fixed argument's new slot.
//
// Unfixed arguments are at negative offsets. In OP_VARARG at 5FKXM, it
// uses `cast_int(base - ci->func) - cl->p->numparams - 1` to compute
// the number of unfixed arguments.
//
// ldo.c--adjust_varargs...(5TCEL)
base = adjust_varargs(L, p, n);
// If the target function not takes unfixed arguments.
else { /* non vararg function */
// 7NEH5
// If the number of arguments passed is less than the number of fixed
// arguments wanted, complete with nils.
for (; n < p->numparams; n++)
setnilvalue(L->top++); /* complete missing arguments */
// Set the offset base to point to the first fixed argument.
base = func + 1;
}
// 53FLN
// Create new call info and point `ci` and `L->ci` to it.
ci = next_ci(L); /* now 'enter' new function */
// 1PYT2
// Store the number of results wanted by the calling context.
ci->nresults = nresults;
// Store the target function's stack slot pointer.
ci->func = func;
// 5ZOOH
// Store the offset base.
// Lua function uses offset base to locate arguments and local variables.
ci->u.l.base = base;
// 6QZ0U
// Point `L->top` and `ci->top` to right after the target function's
// stack frame. Slots between [base, base + fsize) are reserved for all
// fixed arguments and local variables the Lua function uses. Unfixed
// arguments are before `base`.
//
// Unlike for Lua-level function, `L->top` is not needed to compute the
// number of arguments passed inside the target function.
// If less than wanted are passed, fixed arguments will be completed with
// nils at 7NEH5.
// If more than wanted are passed, excessive arguments will cause
// `L->top` to go further at 3NSCL, but is corrected here.
//
L->top = ci->top = base + fsize;
lua_assert(ci->top <= L->stack_last);
// Point to the first instruction.
ci->u.l.savedpc = p->code; /* starting point */
// 5WEZY
// Mark as Lua function.
ci->callstatus = CIST_LUA;
if (L->hookmask & LUA_MASKCALL)
callhook(L, ci);
// Indicate it is a Lua function.
return 0;
}
default: { /* not a function */
checkstackp(L, 1, func); /* ensure space for metamethod */
tryfuncTM(L, func); /* try to get '__call' metamethod */
return luaD_precall(L, func, nresults); /* now it must be a function */
}
}
# ----- ldo.c--luaD_poscall (2V8KP) -----
# Restore previous call info.
# Move results to slots starting from the target function's slot `L->func`.
# Adjust `L->top` to point to right after the results wanted by calling
# context.
#
int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres)
// `ci->nresults` is the number of results wanted by the calling context.
// `firstResult` is the first on-stack result.
// `nres` is the number of on-stack results.
StkId res;
// Get the number of results wanted by calling context.
int wanted = ci->nresults;
if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) {
if (L->hookmask & LUA_MASKRET) {
ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */
luaD_hook(L, LUA_HOOKRET, -1);
firstResult = restorestack(L, fr);
}
L->oldpc = ci->previous->u.l.savedpc; /* 'oldpc' for caller function */
}
// Get the target function's slot.
res = ci->func; /* res == final position of 1st result */
// 7MHXA
// Restore calling context's call info.
L->ci = ci->previous; /* back to caller */
// Move results to slots starting from the target function's slot.
// Adjust `L->top` to point to right after the results wanted.
// ldo.c--moveresults...(68GGE)
/* move results to proper place */
return moveresults(L, firstResult, res, nres, wanted);
# ----- ldo.c--moveresults (68GGE) -----
# Move results to slots starting from the target function's slot.
# Adjust `L->top` to point to right after the results wanted.
#
int moveresults (
lua_State *L,
const TValue *firstResult,
StkId res,
int nres,
int wanted
)
// `res` is the target function's stack slot.
// Slots starting from this slot will be overwritten by results.
//
// `nres` is the number of results on stack returnd by the target function.
//
// `wanted` is the number of results wanted by calling context.
switch (wanted) { /* handle typical cases separately */
case 0: break; /* nothing to move */
case 1: { /* one result needed */
if (nres == 0) /* no results? */
firstResult = luaO_nilobject; /* adjust with nil */
setobjs2s(L, res, firstResult); /* move it to proper place */
break;
}
case LUA_MULTRET: {
int i;
for (i = 0; i < nres; i++) /* move all results to correct place */
setobjs2s(L, res + i, firstResult + i);
// 3NTRR
// Point stack top to right after the last result.
L->top = res + nres;
// Return 0 to indicate the number of results wanted is LUA_MULTRET.
return 0; /* wanted == LUA_MULTRET */
}
default: {
int i;
if (wanted <= nres) { /* enough results? */
for (i = 0; i < wanted; i++) /* move results wanted to correct place */
setobjs2s(L, res + i, firstResult + i);
}
else { /* not enough results; use all of them plus nils */
for (i = 0; i < nres; i++) /* move all results to correct place */
setobjs2s(L, res + i, firstResult + i);
for (; i < wanted; i++) /* complete wanted number of results */
setnilvalue(res + i);
}
break;
}
}
// 53IVT
// Point stack top to right after the last result.
L->top = res + wanted;
// Return 1 to indicate the number of results wanted is fixed.
return 1;
# ----- lapi.h--adjustresults (3RQ2D) -----
# If the number of results wanted is unfixed, and the call info's frame top <
# the stack top, set the call info's frame top to be equal to the stack top.
#
```
#define adjustresults(L,nres) \
{ if ((nres) == LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; }
```
# ----- ldo.c--adjust_varargs (5TCEL) -----
# Move fixed arguments to stack slots after unfixed arguments.
# This is necessary because fixed arguments and local variables are accessed
# via fixed offsets (computed by compiler and encoded in VM opcodes) from an
# offset base. If the target function does not take unfixed arguments, the VM
# points the offset base to right after the target function's slot. This way
# does not work if the target function takes unfixed arguments, in which case
# there are unfixed arguments in the middle between the target function's slot
# and the local variables thus the local variables' offsets to the offset base
# can not be fixed. In this case, the fixed arguments are moved to stack slots
# after the unfixed arguments so that the local variables' offsets still work.
#
static StkId adjust_varargs (lua_State *L, Proto *p, int actual) {
int i;
int nfixargs = p->numparams;
StkId base, fixed;
/* move fixed parameters to final position */
fixed = L->top - actual; /* first fixed argument */
base = L->top; /* final position of first argument */
// Move fixed arguments to slots after unfixed arguments
for (i = 0; i < nfixargs && i < actual; i++) {
setobjs2s(L, L->top++, fixed + i);
setnilvalue(fixed + i); /* erase original copy (for GC) */
}
for (; i < nfixargs; i++)
setnilvalue(L->top++); /* complete missing arguments */
return base;
}
# ----- lvm.c--luaV_execute (3UH1T) -----
# Execute VM instructions.
#
void luaV_execute (lua_State *L)
CallInfo *ci = L->ci;
LClosure *cl;
TValue *k;
StkId base;
// Used at 6XLYC to determine whether it is the first call.
ci->callstatus |= CIST_FRESH; /* fresh invocation of 'luaV_execute" */
newframe: /* reentry point when frame changes (call/return) */
lua_assert(ci == L->ci);
// Get the target function's closure.
cl = clLvalue(ci->func); /* local reference to function's closure */
// Set the constant table to use.
k = cl->p->k; /* local reference to function's constant table */
// Set the offset base.
// The offset base points to the target function's first fixed argument.
// In Lua function, accessing of arguments and local variables are based on
// the offset base.
//
// `ci->u.l.base` is set at 5ZOOH.
//
base = ci->u.l.base; /* local copy of function's base */
/* main loop of interpreter */
for (;;) {
// Updated in `vmfetch`
Instruction i;
// Updated in `vmfetch`
StkId ra;
vmfetch();
vmdispatch (GET_OPCODE(i)) {...}
}
#define vmfetch() { \
i = *(ci->u.l.savedpc++); \
if (L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) \
Protect(luaG_traceexec(L)); \
ra = RA(i); /* WARNING: any stack reallocation invalidates 'ra' */ \
lua_assert(base == ci->u.l.base); \
lua_assert(base <= L->top && L->top < L->stack + L->stacksize); \
}
#define Protect(x) { {x;}; base = ci->u.l.base; }
# ----- lcorolib.c--luaB_cocreate -----
# Create coroutine's lua_State
#
static int luaB_cocreate (lua_State *L)
lua_State *NL;
// Ensure the first argument is a function, i.e. the coroutine function.
luaL_checktype(L, 1, LUA_TFUNCTION);
// Create lua_State and push to stack.
NL = lua_newthread(L);
lstate.c--stack_init...(6KL5G)
// Push the coroutine function to stack.
lua_pushvalue(L, 1); /* move function to top */
// Move the coroutine function to the new state's stack.
// The source stack top will be decremented.
lua_xmove(L, NL, 1); /* move function from L to NL */
// Indicate there is one return value on stack, i.e. the new lua_State.
return 1;
# ----- lstate.c--stack_init (6KL5G) -----
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;
// Set each slot be nil.
for (i = 0; i < BASIC_STACK_SIZE; i++)
setnilvalue(L1->stack + i); /* erase new stack */
// Set stack top.
L1->top = L1->stack;
// Set stack limit.
L1->stack_last = L1->stack + L1->stacksize - EXTRA_STACK;
// 7IEPS
// `base_ci` is the first call info of a Lua thread.
/* initialize first ci */
ci = &L1->base_ci;
ci->next = ci->previous = NULL;
ci->callstatus = 0;
// Set the first call info's `func` be nil because it is special.
// `L1->top` is nil.
ci->func = L1->top;
// 7R4LM
// Set the target function on stack be nil because it is special.
setnilvalue(L1->top++); /* 'function' entry for this 'ci' */
// Set frame limit.
ci->top = L1->top + LUA_MINSTACK;
// Set current call info.
L1->ci = ci;
}
# ----- lcorolib.c--luaB_cowrap -----
# Usage:
# ```
# local run_coroutine = coroutine.wrap(function()
# print("test")
# end)
# run_coroutine()
# ```
#
static int luaB_cowrap (lua_State *L)
// Create lua_State.
luaB_cocreate(L);
// Push `luaB_auxwrap` to stack.
lua_pushcclosure(L, luaB_auxwrap, 1);
// Indicate there is one return value on stack, i.e. `luaB_auxwrap`.
return 1;
# ----- lcorolib.c--luaB_coresume -----
# Move resume arguments to coroutine's stack.
# Resume to coroutine, until the coroutine yields or ends.
# Move a true/false and resume results to calling context's stack.
#
static int luaB_coresume (lua_State *L)
// Get the first on-stack argument, i.e. the coroutine's lua_State.
lua_State *co = getco(L);
int r;
// Resume to the coroutine.
//
// `- 1` is because the first on-stack argument is the coroutine's lua_State.
// Following on-stack arguments are to be passed to the coroutine.
//
// `lua_gettop` counts the slots between (L->top, L->ci->func).
// `L->top` is set at 3NSCL to point to right after the arguments passed.
//
// lcorolib.c--auxresume...(3ZUFQ)
r = auxresume(L, co, lua_gettop(L) - 1);
// If have error.
if (r < 0) {
// Push `false`.
lua_pushboolean(L, 0);
// Insert the `false` before the error message.
lua_insert(L, -2);
// Return the number of on-stack results.
return 2; /* return false + error message */
}
else {
// Push `true`.
lua_pushboolean(L, 1);
// Insert the `true` before on-stack results.
lua_insert(L, -(r + 1));
// Return the number of on-stack results.
return r + 1; /* return true + 'resume' returns */
}
# ----- lcorolib.c--auxresume (3ZUFQ) -----
# Move resume arguments to coroutine's stack.
# Resume to coroutine, until the coroutine yields or ends.
# Move resume results to calling context's stack.
#
static int auxresume (lua_State *L, lua_State *co, int narg)
int status;
if (!lua_checkstack(co, narg)) {
// Push error message.
lua_pushliteral(L, "too many arguments to resume");
// Indicate on-stack result is error message.
return -1; /* error flag */
}
if (lua_status(co) == LUA_OK && lua_gettop(co) == 0) {
// Push error message.
lua_pushliteral(L, "cannot resume dead coroutine");
// Indicate on-stack result is error message.
return -1; /* error flag */
}
// Move resume arguments to the coroutine's stack.
lua_xmove(L, co, narg);
// Resume to the coroutine.
// ldo.c--lua_resume...(2O7W6)
status = lua_resume(co, L, narg);
// If the coroutine ends or yields.
if (status == LUA_OK || status == LUA_YIELD) {
// 7XZWI
// Get number of on-stack results.
int nres = lua_gettop(co);
// If the results overflow the calling context's stack.
if (!lua_checkstack(L, nres + 1)) {
// Remove the results.
lua_pop(co, nres); /* remove results anyway */
// Push error message.
lua_pushliteral(L, "too many results to resume");
// Indicate on-stack result is error message.
return -1; /* error flag */
}
// Move on-stack results from the coroutine to the calling context.
lua_xmove(co, L, nres); /* move yielded values */
// Return number of on-stack results.
return nres;
}
else {
// Move error message to the calling context's stack.
lua_xmove(co, L, 1); /* move error message */
// Indicate on-stack result is error message.
return -1; /* error flag */
}
# ----- ldo.c--lua_resume (2O7W6) -----
# Resume to coroutine, with error recovery.
#
LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs)
int status;
// Store old number of non-yieldable calls.
unsigned short oldnny = L->nny; /* save "number of non-yieldable" calls */
lua_lock(L);
if (L->status == LUA_OK) { /* may be starting a coroutine */
if (L->ci != &L->base_ci) /* not in base level? */
return resume_error(L, "cannot resume non-suspended coroutine", nargs);
}
else if (L->status != LUA_YIELD)
return resume_error(L, "cannot resume dead coroutine", nargs);
// Increment number of C calls.
L->nCcalls = (from) ? from->nCcalls + 1 : 1;
if (L->nCcalls >= LUAI_MAXCCALLS)
return resume_error(L, "C stack overflow", nargs);
luai_userstateresume(L, nargs);
// Yields are allowed only in resumed coroutine.
L->nny = 0; /* allow yields */
api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs);
// 271W9
// ldo.c--luaD_rawrunprotected...(2LSGL)
// ldo.c--resume...(29IQU)
// Call `luaD_rawrunprotected` to call `resume`.
status = luaD_rawrunprotected(L, resume, &nargs);
if (status == -1) /* error calling 'lua_resume'? */
status = LUA_ERRRUN;
else { /* continue running after recoverable errors */
// If is error status, recover lua_State to the lastest protected call.
// If the recovery is successful, unroll.
// ldo.c--recover...(5QRWN)
while (errorstatus(status) && recover(L, status)) {
// Unroll the call stack.
// ldo.c--unroll...(3HYNI)
/* unroll continuation */
status = luaD_rawrunprotected(L, unroll, &status);
}
if (errorstatus(status)) { /* unrecoverable error? */
// Store error status.
L->status = cast_byte(status); /* mark thread as 'dead' */
// Set error message.
seterrorobj(L, status, L->top); /* push error message */
// Set frame limit.
L->ci->top = L->top;
}
else lua_assert(status == L->status); /* normal end or yield */
}
// Restore old number of non-yieldable calls.
L->nny = oldnny; /* restore 'nny' */
// Decrement number of C calls.
L->nCcalls--;
lua_assert(L->nCcalls == ((from) ? from->nCcalls : 0));
lua_unlock(L);
return status;
# ----- ldo.c--resume (29IQU) -----
# Resume to coroutine.
#
static void resume (lua_State *L, void *ud) {
int n = *(cast(int*, ud)); /* number of arguments */
StkId firstArg = L->top - n; /* first argument */
CallInfo *ci = L->ci;
if (L->status == LUA_OK) { /* starting a coroutine? */
// Use `LUA_MULTRET` to point `L->top` to right after all results after
// the call. At 7XZWI, `L->top` is used to compute the number of results.
if (!luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* Lua function? */
luaV_execute(L); /* call it */
}
else { /* resuming from previous yield */
lua_assert(L->status == LUA_YIELD);
L->status = LUA_OK; /* mark that it is running (again) */
// 76D0Z
// Get the coroutine function's slot.
// `ci->extra` is set at 2YSOR.
// `ci->func` is changed at 6ELKB so restoring is needed here.
ci->func = restorestack(L, ci->extra);
if (isLua(ci)) /* yielded inside a hook? */
luaV_execute(L); /* just continue running Lua code */
else { /* 'common' yield */
if (ci->u.c.k != NULL) { /* does it have a continuation function? */
lua_unlock(L);
// Call continuation function.
n = (*ci->u.c.k)(L, LUA_YIELD, ci->u.c.ctx); /* call continuation */
lua_lock(L);
api_checknelems(L, n);
firstArg = L->top - n; /* yield results come from continuation */
}
// ldo.c--luaD_poscall...(2V8KP)
// Restore previous call info.
// Move results to slots starting from the target function's slot.
// Adjust `L->top` to point to right after the results wanted.
luaD_poscall(L, ci, firstArg, n); /* finish 'luaD_precall' */
}
// Unroll.
// ldo.c--unroll...(3HYNI)
unroll(L, NULL); /* run continuation */
}
}
# ----- ldo.c--recover (5QRWN) -----
# Recover lua_State to the lastest protected call with continuation function.
#
static int recover (lua_State *L, int status)
StkId oldtop;
// Find the call info of the latest protected call with continuation
// function.
CallInfo *ci = findpcall(L);
if (ci == NULL) return 0; /* no recovery point */
// 7ZDHI
// Get the target function's slot.
// `ci->extra` is set at 3T2MK.
/* "finish" luaD_pcall */
oldtop = restorestack(L, ci->extra);
luaF_close(L, oldtop);
// Restore the target function's stack top.
// Push error message to stack.
seterrorobj(L, status, oldtop);
// Restore the target function's call info.
L->ci = ci;
// Restore the target function's `allowhook`.
L->allowhook = getoah(ci->callstatus); /* restore original 'allowhook' */
// Allow yields.
L->nny = 0; /* should be zero to be yieldable */
luaD_shrinkstack(L);
// Restore the target function's error function.
// `ci->u.c.old_errfunc` is set at 5I0AI.
L->errfunc = ci->u.c.old_errfunc;
// Indicate have recovered to the latest protected call.
return 1; /* continue running the coroutine */
# ----- ldo.c--unroll (3HYNI) -----
# Unroll a coroutine until the stack is empty or another interruption occurs.
#
static void unroll (lua_State *L, void *ud)
// `ud` is call status.
if (ud != NULL) /* error status? */
// ldo.c--finishCcall (7XCXY)
finishCcall(L, *(int *)ud); /* finish 'lua_pcallk' callee */
while (L->ci != &L->base_ci) { /* something in the stack */
// If is not a Lua function.
// For Lua function, `CIST_LUA` is set at 5WEZY.
if (!isLua(L->ci)) /* C function? */
// Finish the Lua-level C function during unrolling by calling its
// continuation function.
//
// Lua-level C functions found here are guaranteed to have continuation
// function. If the C function calls `luaB_pcall` or `luaB_xpcall`, the
// two call `lua_pcallk` with continuation function. If the C function
// calls `lua_pcallk` without a continuation function, the target
// function will be called using `f_call` at 631AI, which calls
// `luaD_callnoyield`, which increments `L->nyy`, thus forbids yields in
// `lua_yieldk` at 63IHL.
//
// ldo.c--finishCcall (7XCXY)
finishCcall(L, LUA_YIELD); /* complete its execution */
// If is a Lua function.
else { /* Lua function */
// Finish current opcode.
// lvm.c--luaV_finishOp (3ROK8)
luaV_finishOp(L); /* finish interrupted instruction */
// Execute remaining opcodes.
luaV_execute(L); /* execute down to higher C 'boundary' */
}
}
# ----- ldo.c--finishCcall (7XCXY) -----
# Finish a Lua-level C function during unrolling by calling its continuation
# function.
#
static void finishCcall (lua_State *L, int status) {
CallInfo *ci = L->ci;
int n;
/* must have a continuation and must be able to call it */
lua_assert(ci->u.c.k != NULL && L->nny == 0);
/* error status can only happen in a protected call */
// CIST_YPCALL is set at 2JIO8.
lua_assert((ci->callstatus & CIST_YPCALL) || status == LUA_YIELD);
if (ci->callstatus & CIST_YPCALL) { /* was inside a pcall? */
ci->callstatus &= ~CIST_YPCALL; /* continuation is also inside it */
// Restore old error function.
// `ci->u.c.old_errfunc` is set at 5I0AI.
L->errfunc = ci->u.c.old_errfunc; /* with the same error function */
}
// lapi.h--adjustresults...(3RQ2D)
// If the number of results wanted is unfixed, and the call info's frame top
// < the stack top, set the call info's frame top to be equal to the stack
// top.
//
/* finish 'lua_callk'/'lua_pcall'; CIST_YPCALL and 'errfunc' already
handled */
adjustresults(L, ci->nresults);
lua_unlock(L);
// 5VO87
// Call continuation function.
// Continuation function pushes n results to stack,
// stored in `L->top - n` to `L->top - 1`.
// Continuation function returns the number of on-stack results.
//
// At 6KTFG and 2AAB2, continuation function is given.
//
n = (*ci->u.c.k)(L, status, ci->u.c.ctx); /* call continuation function */
lua_lock(L);
api_checknelems(L, n);
// ldo.c--luaD_poscall...(2V8KP)
// Restore previous call info.
// Move results to slots starting from the target function's slot.
// Adjust `L->top` to point to right after the results wanted.
luaD_poscall(L, ci, L->top - n, n); /* finish 'luaD_precall' */
# ----- lvm.c--luaV_finishOp (3ROK8) -----
# Finish execution of an opcode interrupted by an yield.
#
void luaV_finishOp (lua_State *L)
CallInfo *ci = L->ci;
StkId base = ci->u.l.base;
Instruction inst = *(ci->u.l.savedpc - 1); /* interrupted instruction */
OpCode op = GET_OPCODE(inst);
switch (op) { /* finish its execution */
case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_IDIV:
case OP_BAND: case OP_BOR: case OP_BXOR: case OP_SHL: case OP_SHR:
case OP_MOD: case OP_POW:
case OP_UNM: case OP_BNOT: case OP_LEN:
case OP_GETTABUP: case OP_GETTABLE: case OP_SELF: {
setobjs2s(L, base + GETARG_A(inst), --L->top);
break;
}
case OP_LE: case OP_LT: case OP_EQ: {
int res = !l_isfalse(L->top - 1);
L->top--;
if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */
lua_assert(op == OP_LE);
ci->callstatus ^= CIST_LEQ; /* clear mark */
res = !res; /* negate result */
}
lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP);
if (res != GETARG_A(inst)) /* condition failed? */
ci->u.l.savedpc++; /* skip jump instruction */
break;
}
case OP_CONCAT: {
StkId top = L->top - 1; /* top when 'luaT_trybinTM' was called */
int b = GETARG_B(inst); /* first element to concatenate */
int total = cast_int(top - 1 - (base + b)); /* yet to concatenate */
setobj2s(L, top - 2, top); /* put TM result in proper position */
if (total > 1) { /* are there elements to concat? */
L->top = top - 1; /* top is one after last element (at top-2) */
luaV_concat(L, total); /* concat them (may yield again) */
}
/* move final result to final position */
setobj2s(L, ci->u.l.base + GETARG_A(inst), L->top - 1);
L->top = ci->top; /* restore top */
break;
}
case OP_TFORCALL: {
lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_TFORLOOP);
L->top = ci->top; /* correct top */
break;
}
case OP_CALL: {
if (GETARG_C(inst) - 1 >= 0) /* nresults >= 0? */
L->top = ci->top; /* adjust results */
break;
}
case OP_TAILCALL: case OP_SETTABUP: case OP_SETTABLE:
break;
default: lua_assert(0);
}
# ----- lcorolib.c--luaB_yield (5FE7E) -----
# Yield from coroutine.
#
static int luaB_yield (lua_State *L)
// lcorolib.c--lua_yield...(70HS9)
return lua_yield(L, lua_gettop(L));
# ----- lcorolib.c--lua_yield (70HS9) -----
# Macro for `lua_yieldk`.
# Continuation function argument `ctx` be 0.
# Continuation function `k` be NULL.
```
// lcorolib.c--lua_yieldk...(3E6PN)
#define lua_yield(L,n) lua_yieldk(L, (n), 0, NULL)
```
# ----- lcorolib.c--lua_yieldk (3E6PN) -----
# Yield from coroutine.
#
LUA_API int lua_yieldk (
lua_State *L,
int nresults,
lua_KContext ctx,
lua_KFunction k
)
CallInfo *ci = L->ci;
luai_userstateyield(L, nresults);
lua_lock(L);
api_checknelems(L, nresults);
// 63IHL
// If yields are forbidden.
if (L->nny > 0) {
if (L != G(L)->mainthread)
// Will jump to 7KZPY.
luaG_runerror(L, "attempt to yield across a C-call boundary");
else
// Will jump to 7KZPY.
luaG_runerror(L, "attempt to yield from outside a coroutine");
}
// Mark as yield.
L->status = LUA_YIELD;
// 2YSOR
// Store the target function's slot.
// Used at 76D0Z.
ci->extra = savestack(L, ci->func); /* save current 'func' */
if (isLua(ci)) { /* inside a hook? */
api_check(L, k == NULL, "hooks cannot continue after yielding");
}
else {
if ((ci->u.c.k = k) != NULL) /* is there a continuation? */
// Store continuation function's argument.
ci->u.c.ctx = ctx; /* save context */
// 6ELKB
// At 7XZWI, `auxresume` considers all slots after the function slot as
// results.
// So change `ci->func` to make it take `nresults` results only.
ci->func = L->top - nresults - 1; /* protect stack below results */
// Jump to 271W9.
luaD_throw(L, LUA_YIELD);
}
lua_assert(ci->callstatus & CIST_HOOKED); /* must be inside a hook */
lua_unlock(L);
return 0; /* return to 'luaD_hook' */
# ----- OP_CALL -----
vmcase(OP_CALL)
// Get the number of arguments passed to the function plus 1.
// The number of arguments passed is determined by compiler and encoded in
// opcode. It is used at 3NSCL below to affect `L->top`. `L-top` is then used
// to compute the number of arguments passed in Lua-level C functions using
// `lua_gettop`, or at 5NTGX for Lua functions.
int b = GETARG_B(i);
// 7KOMK
// Get the number of results wanted by calling context.
// OP_CALL's argument C is determined by the calling context, not by the
// target function's return statement.
int nresults = GETARG_C(i) - 1;
// 3NSCL
// If the number of arguments passed is fixed,
// point stack top to right after the arguments.
//
// If the number of arguments passed is unfixed, `L->top` should be set by
// previous OP_CALL's corresponding OP_RETURN in `luaD_poscall moveresults`
// at 3NTRR.
//
// In `luaD_precall` at 5NTGX, `cast_int(L->top - func) - 1` computes the
// number of arguments passed to the function.
//
if (b != 0) L->top = ra+b; /* else previous instruction set top */
// ldo.c--luaD_precall...(7KDMP)
if (luaD_precall(L, ra, nresults)) { /* C function? */
// If the number of results wanted by calling context is fixed.
if (nresults >= 0)
// 3G9C6
// Point `L->top` to right after the current function's stack frame.
// `ci->top` is set at 2A3I0 and 6QZ0U before executing the current
// function.
//
// The same is done for Lua function at 5WFHY.
//
L->top = ci->top; /* adjust results */
// Restore current function's offset base.
Protect((void)0); /* update 'base' */
}
else { /* Lua function */
// Point `ci` to the target function's call info.
ci = L->ci;
// Re-enter to execute the target function.
goto newframe; /* restart luaV_execute over new Lua function */
}
vmbreak;
# ----- OP_VARARG -----
vmcase(OP_VARARG)
// Get the number of values wanted.
int b = GETARG_B(i) - 1; /* required results */
int j;
// 5FKXM
// Get the number of unfixed arguments.
int n = cast_int(base - ci->func) - cl->p->numparams - 1;
if (n < 0) /* less arguments than parameters? */
n = 0; /* no vararg arguments */
if (b < 0) { /* B == 0? */
// Take all unfixed arguments.
b = n; /* get all var. arguments */
Protect(luaD_checkstack(L, n));
ra = RA(i); /* previous call may change the stack */
// 6TNUV
// This is for `return ...` situation.
L->top = ra + n;
}
for (j = 0; j < b && j < n; j++)
setobjs2s(L, ra + j, base - n + j);
for (; j < b; j++) /* complete required results with nil */
setnilvalue(ra + j);
vmbreak;
# ----- OP_RETURN -----
vmcase(OP_RETURN)
// Get number of on-stack results plus 1.
int b = GETARG_B(i);
// Close open upvalues.
if (cl->p->sizep > 0) luaF_close(L, base);
// ldo.c--luaD_poscall...(2V8KP)
// The return value indicates wether the number of results wanted by the
// calling context is fixed.
b = luaD_poscall(L, ci, ra, (b != 0 ? b - 1 : cast_int(L->top - ra)));
// 6XLYC
if (ci->callstatus & CIST_FRESH) /* local 'ci' still from callee */
// Leave `L->top` unchanged to let caller determine the number of results.
return; /* external invocation: return */
else { /* invocation via reentry: continue execution */
// Set previous call info as current.
// `L->ci` is pointed to the previous call info in `luaD_poscall` above.
ci = L->ci;
// 3G9C6
// If the number of results wanted by the calling function is fixed,
// point `L->top` to right after the previous function's stack frame.
// `ci->top` is set at 2A3I0 and 6QZ0U before executing the calling
// function. The same is done for Lua-level C function at 5WFHY.
//
// If the number of results wanted is fixed, `L->top` is set in
// `luaD_poscall moveresults` at 53IVT to point to right after results.
//
// If the number of results wanted is unfixed, `L->top` is set in
// `luaD_poscall moveresults` at 3NTRR to point to right after results.
//
if (b) L->top = ci->top;
lua_assert(isLua(ci));
lua_assert(GET_OPCODE(*((ci)->u.l.savedpc - 1)) == OP_CALL);
goto newframe; /* restart luaV_execute over new Lua function */
}
Comments: