既然Lua虚拟机模拟的是CPU的运作,那么Lua栈模拟的就是内存的角色.在Lua内部,参数的传递是通过Lua栈,同时Lua与C等外部进行交互的时候也是使用的栈.,先关注的是Lua栈的分配,管理和相关的数据结构.

lua虚拟机在初始化创建lua_State结构体时,会走到stack_init函数中,这个函数主要就是对Lua栈和CallInfo数组的初始化:

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->end_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;
}

可以看到的是,初始化了两个数组,分别保存Lua栈和CallInfo结构体数组.

其中,与Lua栈相关的lua_State结构体成员变量有base,stack,top,lastfree,stack保存的是数组的初始位置,base会根据每次函数调用的情况发生变化,top指针指向的是当前第一个可用的栈位置,每次向栈中增加/删减元素都要对应的增减top指针,lastfee指针指向的书Lua栈的最后位置.

CallInfo结构体,是每次有函数调用时都会去初始化的一个结构体,它的成员变量中,也有top,base指针,同样的是指向Lua栈的位置,所不同的是,它关注的仅是函数调用时的相关位置.从代码中可以看出,CallInfo数组是有限制的,换言之,在Lua中的嵌套函数调用层次也是有限制,不能超过一定数量.

首先看f_parser函数:

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

f_parser函数的最后两句,将分析完毕之后的结构Closure指针压入了Lua栈.

再来看luaD_precall函数,这里为将代码放入Lua虚拟机中执行准备了相关数据,我们只截取其中的一部分来看:

int luaD_precall (lua_State *L, StkId func, int nresults) {
….
if (!cl->isC) { /* Lua function? prepare its call */
CallInfo *ci;
StkId st, base;
Proto *p = cl->p; // 1) 根据函数的参数类型,计算出该CallInfo的base指针位置
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 */
} // 2) 分配一个新的CallInfo结构体,用于保存此次函数调用的相关信息:top,base指针,func函数
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); // 3) LuaState的PC指针指向函数原型的代码数组
L->savedpc = p->code; /* starting point */
// …..
return PCRLUA;
}

到这一步,跟某次具体的Lua代码执行相关的代码(保存在Proto的code数组中)和执行时所需环境(Lua栈),就已经准备完毕了.后面就是进入Lua虚拟机的主循环中解释执行代码了.

lua栈的更多相关文章

  1. 通过lua栈了解lua与c的交互

    lua是如何执行的 其中分析.执行部分都是c语言实现的. lua与c的关系 lua的虚拟机是用c语言实现的,换句话说一段lua指令最终在执行时都是当作c语言来执行的,lua的global表,函数调用栈 ...

  2. lua和C++交互的lua栈操作——以LuaTinker为例

    一. -- C++类注册函数(LuaTinker) 的lua栈操作: -- lua栈内容(执行到pop语句) 栈地址 <--执行语句 space_name[name] = t1 -- (2b8) ...

  3. Lua 栈的理解

    提到C++与lua互调,不可不提栈. 栈是C++和Lua相互通讯的一个地方. 首先这个栈并不是传统意义上的栈(传统的栈需要放同一种数据类型,但在网上的某些资料说,每个栈元素是一个联合体). 栈从上向下 ...

  4. Lua 栈中元素的位置

    Lua与C.C#等的交互是通过栈来实现的,每次插入元素都是放在栈顶(top),至于元素的index,可以使用正数和负数两种方式, 如取栈底开始至第index个元素 -index = gettop - ...

  5. c调用 lua 栈操作

    转自https://www.cnblogs.com/ringofthec/archive/2010/10/22/lua.html 打算记录一些lua_api, 可能会觉得lua文档中已经说的很清楚了, ...

  6. lua 栈最后调用的函数,用于看调试信息

    lua_getinfo int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar); 返回一个指定的函数或函数调用的信息. 当用于取 ...

  7. Lua的栈及基本栈操作

    Lua的栈及基本栈操作 https://blog.csdn.net/mydriverc2/article/details/51134737 https://blog.csdn.net/mydriver ...

  8. lua解释执行脚本流程

    #include "lua.hpp" #include <iostream> using namespace std; #pragma comment(lib, &qu ...

  9. Lua和C++交互详细总结

    转自:http://cn.cocos2d-x.org/tutorial/show?id=1474 一.Lua堆栈 要理解Lua和C++交互,首先要理解Lua堆栈. 简单来说,Lua和C/C++语言通信 ...

随机推荐

  1. quartz(转)

    1.   CronTrigger时间格式配置说明 CronTrigger配置格式: 格式: [秒] [分] [小时] [日] [月] [周] [年] 序号 说明 是否必填 允许填写的值 允许的通配符 ...

  2. 有料面试题之--Object里面的方法

    阿里的面试题里面有个题很奇妙:你知道Object类里面有哪些方法吗? 绝大部分猿类都知道 有hashcode .equals .clone.toString 只有部分人会回答有 wait和notify ...

  3. 我做的一个websocket的demo(php server)

    notice: 通过命令行执行php文件  如 php -q c:\path\server.php 通过本地web服务器访问 http://127.0.0.1/websocket/index.php即 ...

  4. [JSOI2008]Blue Mary的战役地图

    嘟嘟嘟 当看到n <= 50 的时候就乐呵了,暴力就行了,不过最暴力的方法是O(n7)……然后加一个二分边长达到O(n6logn),然后我们接着优化,把暴力比对改成O(1)的比对hash值,能达 ...

  5. Hadoop学习之路(一)理论基础和逻辑思维

    三个题目 第一题 问题描述 统计出当前这个一行一个IP的文件中,到底哪个IP出现的次数最多 解决思路 //必须要能读取这个内容 BufferedReader br = new BuffedReader ...

  6. ethers.js-1

    https://docs.ethers.io/ethers.js/html/ What is ethers.js The ethers.js library aims to be a complete ...

  7. windows7使用Sphinx+PHP+MySQL详细介绍

    安装(Windows) 1.官方下载 Sphinx下载地址: 下载 2.解压并重命名 此处下载版本为3.0.3,将 sphinx 文件夹命名为sphinx 3.文件夹目录介绍 sphinx --api ...

  8. Red Hat Linux 挂载外部资源

    在我们安装的Red Hat Linux 中.当中一半机器为最主要的server配置,没有桌面环境.在从U盘上复制文件的时候可就犯难了.在网上查了查才知道.要訪问U盘就必须先将它们挂载到Linux系统的 ...

  9. Linux Shell常用技巧(一)

    一.    特殊文件: /dev/null和/dev/tty Linux系统提供了两个对Shell编程非常有用的特殊文件,/dev/null和/dev/tty.其中/dev/null将会丢掉所有写入它 ...

  10. Redis 可视化工具 Redis Desktop Manager 和 treeNMS 的使用

    这里介绍两个 Redis 可视化工具.Redis Desktop Manager 和 treeNMS. 一.Redis Desktop Manager 下载地址:https://redisdeskto ...