lua源码注释1【转】
来源:互联网 发布:php 异步请求类 编辑:程序博客网 时间:2024/06/11 07:10
最近读了点lua的源码,打算记录下来,将来也知道自己这一段干了啥。
其实我以前也试图读过lua源码,不过一直没有找对下手方向,比如我一直试图从main下手,这个是错误的,还没有进行正题,就被一大堆初始化给搞晕了,加之决心不大,就这样一直拖着没有看。
不过最近因为工作的原因,熟悉了lua的c api,发现从c api入手是个不错的方法。但是首先,还是要熟悉下Lua里面的基础数据结构:
lua里面所有的值都是存放在TValue里的,TValue是所谓的tagged values。tt域表示的是值的类型(lua的8种基本类型),value域是表示具体的值,这个是一个union,
关于这两个结构,可以浏览下lobject.h,里面有详细的说明和lua里面的用法,通过宏来操作。
lstate.h里有global_State,这个是整个运行环境中只有一份的。lua_State,表示每个thread(这是一个coroutine,并非posix意义上的thread)的state。还有GCObject,lua有gc机制,GCObject包括了table, userdata(重型),string, function和thread。
接下来就从lapi.c这个文件起。
lua和c交互方式比较特别,是通过一个虚拟栈来交互的,通过阅读lapi.c,可以了解下这个虚拟栈的运作,为更深入的理解lua source打基础,这个index2adr的函数,是基础中的基础,它定义了栈的标识(即index)是如何转化为实际的地址的。
如果idx > 0,那么从栈底开始向上算,如果idx <= 0还大于LUA_REGISTRYINDEX(-10000),那么从栈顶开始向下数,栈上每个元素都是一个指向TValue的指针。
同时,这个函数还可以处理pseudo-indices,这是一类特殊的index,这个index不表示栈上的值,而表示lua registry,这个是一个全局的表,只对程序员可见,lua脚本没有办法使用。LUA_ENVIRONINDEX和GLOBALSINDEX来取运行时环境表和全局表,最后还有一招,似乎很少有人使用,就是可以取当前函数的upvalue,第n个upvalue就是用LUA_GLOBALSINDEX - n。
另外,这里最最重要的一点是,按照文档,传入-1表示的是栈顶元素,也就是说L->top-1是栈顶元素,L->top表示栈上下一个待使用空间。
接下来一段都比较好懂,直到
这里出现了个L->ci->top,ci是个CallInfo结构,看source code上的注释是表示当前的运行的函数的信息。L->ci->top和L->top的关系是什么,我现在还没有把源码看完,不敢下定论,我的感觉是L->ci->top表示了当前函数最多需要使用的栈空间,我就用到L->ci->top,不需要更多了。
接下来的函数又比较简单,顺着读就可以了。不要受诱惑,一层一层代码看下去,人脑不是电脑,管理不了那么多层递归。我觉得这些函数中值得一提的是
这个函数名为insert,实际上栈上并没有增加新的元素,不过是将栈顶的值交换到idx位置,而在L->top上那个元素处于无人管理的状态,等待gc回收。
在lua_call函数之前有一个宏
佐证了我之前的想法,栈上预留的空间,要大于返回值的个数减掉参数的个数。
其实我以前也试图读过lua源码,不过一直没有找对下手方向,比如我一直试图从main下手,这个是错误的,还没有进行正题,就被一大堆初始化给搞晕了,加之决心不大,就这样一直拖着没有看。
不过最近因为工作的原因,熟悉了lua的c api,发现从c api入手是个不错的方法。但是首先,还是要熟悉下Lua里面的基础数据结构:
/*** Tagged Values*/#define TValuefields Value value; int tttypedef struct lua_TValue { TValuefields;} TValue;
lua里面所有的值都是存放在TValue里的,TValue是所谓的tagged values。tt域表示的是值的类型(lua的8种基本类型),value域是表示具体的值,这个是一个union,
/*** Union of all Lua values*/typedef union { GCObject *gc; void *p; lua_Number n; int b;} Value;
关于这两个结构,可以浏览下lobject.h,里面有详细的说明和lua里面的用法,通过宏来操作。
lstate.h里有global_State,这个是整个运行环境中只有一份的。lua_State,表示每个thread(这是一个coroutine,并非posix意义上的thread)的state。还有GCObject,lua有gc机制,GCObject包括了table, userdata(重型),string, function和thread。
/*** Union of all collectable objects*/union GCObject { GCheader gch; union TString ts; union Udata u; union Closure cl; struct Table h; struct Proto p; struct UpVal uv; struct lua_State th; /* thread */};
接下来就从lapi.c这个文件起。
static TValue *index2adr (lua_State *L, int idx) { if (idx > 0) { TValue *o = L->base + (idx - 1); api_check(L, idx <= L->ci->top - L->base); if (o >= L->top) return cast(TValue *, luaO_nilobject); else return o; } else if (idx > LUA_REGISTRYINDEX) { api_check(L, idx != 0 && -idx <= L->top - L->base); return L->top + idx; } else switch (idx) { /* pseudo-indices */ case LUA_REGISTRYINDEX: return registry(L); case LUA_ENVIRONINDEX: { Closure *func = curr_func(L); sethvalue(L, &L->env, func->c.env); return &L->env; } case LUA_GLOBALSINDEX: return gt(L); default: { Closure *func = curr_func(L); idx = LUA_GLOBALSINDEX - idx; return (idx <= func->c.nupvalues) ? &func->c.upvalue[idx-1] : cast(TValue *, luaO_nilobject); } }}
lua和c交互方式比较特别,是通过一个虚拟栈来交互的,通过阅读lapi.c,可以了解下这个虚拟栈的运作,为更深入的理解lua source打基础,这个index2adr的函数,是基础中的基础,它定义了栈的标识(即index)是如何转化为实际的地址的。
如果idx > 0,那么从栈底开始向上算,如果idx <= 0还大于LUA_REGISTRYINDEX(-10000),那么从栈顶开始向下数,栈上每个元素都是一个指向TValue的指针。
同时,这个函数还可以处理pseudo-indices,这是一类特殊的index,这个index不表示栈上的值,而表示lua registry,这个是一个全局的表,只对程序员可见,lua脚本没有办法使用。LUA_ENVIRONINDEX和GLOBALSINDEX来取运行时环境表和全局表,最后还有一招,似乎很少有人使用,就是可以取当前函数的upvalue,第n个upvalue就是用LUA_GLOBALSINDEX - n。
另外,这里最最重要的一点是,按照文档,传入-1表示的是栈顶元素,也就是说L->top-1是栈顶元素,L->top表示栈上下一个待使用空间。
接下来一段都比较好懂,直到
LUA_API int lua_checkstack (lua_State *L, int size) { int res; lua_lock(L); if ((L->top - L->base + size) > LUAI_MAXCSTACK) res = 0; /* stack overflow */ else { luaD_checkstack(L, size); if (L->ci->top < L->top + size) L->ci->top = L->top + size; res = 1; } lua_unlock(L); return res;}
这里出现了个L->ci->top,ci是个CallInfo结构,看source code上的注释是表示当前的运行的函数的信息。L->ci->top和L->top的关系是什么,我现在还没有把源码看完,不敢下定论,我的感觉是L->ci->top表示了当前函数最多需要使用的栈空间,我就用到L->ci->top,不需要更多了。
接下来的函数又比较简单,顺着读就可以了。不要受诱惑,一层一层代码看下去,人脑不是电脑,管理不了那么多层递归。我觉得这些函数中值得一提的是
LUA_API void lua_insert (lua_State *L, int idx) { StkId p; StkId q; lua_lock(L); p = index2adr(L, idx); api_checkvalidindex(L, p); for (q = L->top; q>p; q--) setobjs2s(L, q, q-1); setobjs2s(L, p, L->top); lua_unlock(L);}
这个函数名为insert,实际上栈上并没有增加新的元素,不过是将栈顶的值交换到idx位置,而在L->top上那个元素处于无人管理的状态,等待gc回收。
在lua_call函数之前有一个宏
#define checkresults(L,na,nr) \ api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)))
佐证了我之前的想法,栈上预留的空间,要大于返回值的个数减掉参数的个数。
0 0
- lua源码注释1【转】
- lua源码剖析1【转】
- lua注释
- Lua注释
- Lua源码分析(1)
- lua源码剖析2【转】
- lua源码剖析3【转】
- Lua源码分析(1) -- 简介
- 《lua源码赏析》笔记 -1
- eCryptfs源码注释(1)
- lua的注释
- Hello.lua注释
- lua的注释
- LUA注释语法
- Lua 源码剖析第1天
- LUA源码分析三:table分析(1)
- LUA源码分析三:table分析(1)
- lua源码阅读(1)----概览
- Oracle中的游标(光标)
- linux上mysql忘记密码
- Kissy中的ajax异步提交
- IOS_加速计_CoreMotion框架_单例_时钟_Get+异步请求+Json
- JavaScript学习第一弹:【图片轮播实现】
- lua源码注释1【转】
- freemarker报错之八
- 面向对象-Object类
- [LeetCode]Candy
- 机器学习--学习笔记(四)--支持向量机
- C语言文件读写命令
- Win 8 系统下 Weblogic server 12c 的下载安装与配置——Windows J2EE开发安装序列之六
- BaiduMap_SDK_DEMO_3.0.0_for_Xamarin.Android_by_imknown
- lua和C++相互交换数据1 【转】