既然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. SAP 前端技术的演化史简介

    Jerry之前曾经写过一篇微信公众号文章,题目叫<> 关注我的公号"汪子熙"后,在历史菜单"前端开发相关"里即可找到这篇文章: 该文章简单回顾了SA ...

  2. 【理解】 Error 10053和 Error 10054

    1. 10053 这个错误码的意思是:  A established connection was aborted by the software in your host machine, 一个已建 ...

  3. [JSOI2008]火星人

    嘟嘟嘟 嗯. splay维护哈希. 如题,用splay维护哈希,查找的时候二分.所以复杂度是取决于询问复杂度:\(O(n \log^ 2{n})\). 这道题还有一个技巧,就是一个节点记录的是他的子树 ...

  4. [USACO09JAN]Earthquake Damage

    嘟嘟嘟 刚开始因为没看到只能走没有损坏的农场,磨叽了20多分钟……不管了,写题解吧. 首先如果一个点不能到达原点,那么和他相邻的点也不能到达原点,所以刚开始我们把不能走的点和他相邻的点都打上标记,然后 ...

  5. 【转】Android中获取应用程序(包)的信息-----PackageManager的使用(一)

    转载请注明出处:http://blog.csdn.net/qinjuning       本节内容是如何获取Android系统中应用程序的信息,主要包括packagename.label.icon.占 ...

  6. virtualbox+vagrant学习-2(command cli)-7-vagrant login命令

    Login ⚠️该命令已经弃用了,别名为vagrant cloud auth login.看本博客的 格式: vagrant cloud auth login [options] 登录命令用于使用Ha ...

  7. 为什么 token可以防止 csrf?

    Token被用户端放在Cookie中(不设置HttpOnly),同源页面每次发请求都在请求头或者参数中加入Cookie中读取的Token来完成验证.CSRF只能通过浏览器自己带上Cookie,不能操作 ...

  8. c++——register关键字、struct类型、bool关键字、三目运算符

    register关键字增强 //register关键字 请求编译器让变量a直接放在寄存器里面,速度快 //在c语言中 register修饰的变量 不能取地址,但是在c++里面做了内容 /* //1 r ...

  9. java 接口的概念

    一:概念 接口是功能的集合.同样可以看做一种数据类型,是比抽象类更为抽象的“类”. 接口描述应该具备的方法,并没有具体的实现.具体实现由接口的实现类(相当于接口的子类来完成). 好处: 使功能和实现分 ...

  10. java基础二 java的跨平台特性

    一:java跨平台的特性: 1.生成不平台无关系的字节码. 2.通过和平台有关的jvm即java虚拟机来执行字节码.jvm不跨平台. 图示: 疑问:1.为什么我们不直接写字节码? 因为字节码只有jvm ...