Lua5.2源代码解析
源代码版本:lua-5.2.0
一、概览
1、lua脚本中暴露的库相关
lbaselib.c - 基础函数库(方便使用lua内部的功能)
lbitlib.c - 位运算库
lcorolib.c - 协程库
lstrlib.c - 字符串库,提供通用字符串处理功能
lstring.c - 字符串表(保存所有由Lua操作的字符串集合)
lmathlib.c - 数学库
loslib.c - 操作系统相关库,时间、环境、语言、执行程序等
liolib.c - 输入输出库
loadlib.c - 模块库(实现require函数,package函数)
ldblib.c - 调试库
ldebug.c - 调试接口:包含访问调试钩子的函数(lua_sethook/lua_gethook/lua_gethookcount),访问运行时堆栈信息的函数(lua_getstatck/lua_getlocal/lua_setlocal),检查字节码函数(luaG_checkopenop/luaG_checkcode),和抛出错误的函数(luaG_typeerror/luaG_concaterror/luaG_aritherror/luaG_ordererror/luaG_errormsg/luaG_runerror)
lapi.c - Lua的API.实现Lua C API(lua_*函数)集合
lauxlib.c - 定义所有的luaL_*函数集
2、lua runtime的数据结构相关
lfunc.c - 包装原型和闭包的辅助函数
ltable.c - Lua表实现(哈希)
lobject.c - 一些针对Lua对象的通用函数。包括数据类型到字符串转换函数,纯数据相等测试函数(luaO_rawequalObj),和日志基础2(luaO_log2)
ltm.c - 标记原语方法。实现对象访问原语方法(metathods)
3、编译前端
llex.c - 词法分析器,被lparser.c使用,接口LUAI_FUNC void luaX_next (LexState *ls);
lparser.c - Lua语法检查器,接口 Proto *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, Dyndata *dyd, const char *name, int firstchar);
lundump.c - 加载预编译后的Lua代码块,函数luaU_undump,加载一个预编译后的代码块;luaU_header(被luaU_undump使用的内部函数),用来检查函数头部。
ldump.c - 保存预编译后的Lua代码块。函数luaU_dump,使用预编译后的代码字符串展示一个函数;
lcode.c - Lua的代码生成器。被lparser.c使用,static int luaK_code (FuncState *fs, Instruction i) 用于写入一条指令
顺序:lex--parse--code--dump
4、虚拟机、运行时相关
lopcodes.c - Lua虚拟机的操作码。定义所有操作符的名称和信息(使用luaP_opnames和luaP_opmodes两个表保存)
lvm.c - Lua虚拟机。执行字节码(luaV_execute)。也暴漏一些lapi.c可能用到的函数(例如:luaV_concat)
ldo.c - Lua的栈和调用结构。控制函数调用(luaD_call/luaD_pcall),栈增长,协同代码的同步
lstate.c - 全局上下文信息即 符号表(函数表、变量表、线程等). 包括打开和关闭LUA上线文的函数(lua_newstate/lua_close)和lua线程函数(luaE_newthread/luaE_freethread)
lmem.c - 内存管理的接口.通过封装内存分配函数,实现了luaM_realloc / luaM_growaux_两个函数.
lgc.c - 垃圾回收器(内存管理)
5、外部封装
lua.c - Lua独立解释器
luac.c - Lua编译器(保存字节码到一个文件,也可以列出字节码)
6、其他
lzio.c - 一个通用的带缓冲区的输入流接口
linit.c - 实现luaL_openlibs方法,便于在C语言中加载上述模块
lctype.c 判断类型
二、主流程
第一阶段:main---load----词法、语法解析、parser内会生成需要的指令集
第二阶段:docall----虚拟机内的luaV_execute
三、runtime的实现
1、vc中的一个典型调用栈信息如下:
> lua1.exe!luaV_execute(lua_State * L=0x00035c28) Line 521 C
lua1.exe!luaD_call(lua_State * L=0x00035c28, lua_TValue * func=0x00035e00, int nResults=-1, int allowyield=0) Line 393 + 0x9 bytes C
lua1.exe!f_call(lua_State * L=0x00035c28, void * ud=0x0013f4a0) Line 920 + 0x18 bytes C
lua1.exe!luaD_rawrunprotected(lua_State * L=0x00035c28, void (lua_State *, void *)* f=0x00424a60, void * ud=0x0013f4a0) Line 133 + 0x1f bytes C
lua1.exe!luaD_pcall(lua_State * L=0x00035c28, void (lua_State *, void *)* func=0x00424a60, void * u=0x0013f4a0, int old_top=40, int ef=32) Line 591 + 0x11 bytes C
lua1.exe!lua_pcallk(lua_State * L=0x00035c28, int nargs=0, int nresults=-1, int errfunc=3, int ctx=0, int (lua_State *)* k=0x00000000) Line 946 + 0x20 bytes C
lua1.exe!docall(lua_State * L=0x00035c28, int narg=0, int nres=-1) Line 179 + 0x19 bytes C
lua1.exe!handle_script(lua_State * L=0x00035c28, char * * argv=0x00035ba0, int n=1) Line 341 + 0xf bytes C
lua1.exe!pmain(lua_State * L=0x00035c28) Line 469 + 0x17 bytes C
lua1.exe!luaD_precall(lua_State * L=0x00035c28, lua_TValue * func=0x00035de0, int nresults=1) Line 317 + 0x9 bytes C
lua1.exe!luaD_call(lua_State * L=0x00035c28, lua_TValue * func=0x00035de0, int nResults=1, int allowyield=0) Line 392 + 0x11 bytes C
lua1.exe!f_call(lua_State * L=0x00035c28, void * ud=0x0013fe48) Line 920 + 0x18 bytes C
lua1.exe!luaD_rawrunprotected(lua_State * L=0x00035c28, void (lua_State *, void *)* f=0x00424a60, void * ud=0x0013fe48) Line 133 + 0x1f bytes C
lua1.exe!luaD_pcall(lua_State * L=0x00035c28, void (lua_State *, void *)* func=0x00424a60, void * u=0x0013fe48, int old_top=8, int ef=0) Line 591 + 0x11 bytes C
lua1.exe!lua_pcallk(lua_State * L=0x00035c28, int nargs=2, int nresults=1, int errfunc=0, int ctx=0, int (lua_State *)* k=0x00000000) Line 946 + 0x20 bytes C
lua1.exe!main(int argc=2, char * * argv=0x00035ba0) Line 495 + 0x13 bytes C
2、基本交互逻辑
vm循环取出一个一个的Instruction,之后一个巨大的switch来解释这个Instruction(lua 5.2是基于寄存器的指令集),即经典的fetch---execute循环。
特殊的指令:
1》函数调用指令:遇到函数调用时(lua中调用),要用c代码模拟出硬件执行代码时的栈结构。
基本上每次增加一个活动记录时要设置好相应的闭包信息和执行环境,设置好相应的符号表,做好参数的检查,必要时GC一下
2》协程指令 :每次有create调用时就新建一个lua_state,全局栈维护这些stack信息
resume时 luaB_coresume---auxresume---lua_resume---luaB_yield
lua1.exe!lua_yieldk(lua_State * L=0x0003e698, int nresults=1, int ctx=0, int (lua_State *)* k=0x00000000) Line 556 C
lua1.exe!luaB_yield(lua_State * L=0x0003e698) Line 99 + 0x1a bytes C
lua1.exe!luaD_precall(lua_State * L=0x0003e698, lua_TValue * func=0x0003f3f8, int nresults=-1) Line 317 + 0x9 bytes C
lua1.exe!luaV_execute(lua_State * L=0x0003e698) Line 744 + 0x34 bytes C
lua1.exe!resume(lua_State * L=0x0003e698, void * ud=0x0003f3d8) Line 496 + 0x9 bytes C
lua1.exe!luaD_rawrunprotected(lua_State * L=0x0003e698, void (lua_State *, void *)* f=0x004348d0, void * ud=0x0003f3d8) Line 133 + 0x1f bytes C
lua1.exe!lua_resume(lua_State * L=0x0003e698, lua_State * from=0x00035c28, int nargs=2) Line 531 + 0x1d bytes C
> lua1.exe!auxresume(lua_State * L=0x00035c28, lua_State * co=0x0003e698, int narg=2) Line 31 + 0x11 bytes C
lua1.exe!luaB_coresume(lua_State * L=0x00035c28) Line 53 + 0x1d bytes C
四、解释器
1、main函数
line484: lua.c
lua_newstate:全局和线程栈状态的初始化
lua_State *L = luaL_newstate(); // 创建全局的运行时信息
lua_pushcfunction(L, &pmain); // 创建当前栈顶的函数闭包
lua_pushinteger(L, argc); // 参数入栈
lua_pushlightuserdata(L, argv); /* 2nd argument */
status = lua_pcall(L, 2, 1, 0); // 运行时执行一个lua函数
result = lua_toboolean(L, -1); /* get result */
finalreport(L, status);
lua_close(L); // 释放内存等扫尾工作
2、lua_pcall详情
1》参数检查
2》luaD_pcall --------luaD_rawrunprotected---f_call----luaD_call---luaD_precall---pmain
luaL_checkversion(L); // 验证虚拟机
lua_gc(L, LUA_GCSTOP, 0); /* stop collector during initialization */
luaL_openlibs(L); // 初始化内置库 loadedlibs是默认打开的功能表
lua_gc(L, LUA_GCRESTART, 0);
handle_script -------执行主脚本
luaL_loadfile------docall(一堆的栈操作)----luaV_execute:lvm.c // 虚拟机的执行引擎
Lua5.2源代码解析相关推荐
- Spring源代码解析(收藏)
Spring源代码解析(收藏) Spring源代码解析(一):IOC容器:http://www.iteye.com/topic/86339 Spring源代码解析(二):IoC容器在Web容器中的启 ...
- Android源代码解析之(四)--gt;HandlerThread
转载请标明出处:一片枫叶的专栏 上一篇文章中我们解说了AsyncTast的基本使用以及实现原理,我们知道AsyncTask内部是通过线程池和Handler实现的.通过对线程池和handler的封装实现 ...
- Tomcat源代码解析系列
学web也有一段时间了.为了从底层了解web应用在Tomcat中的执行,决定看一下Tomcat的源代码參见<How Tomcat works> 和大牛博客.对大体架构有了一定的了解, ...
- 【backtrader源码解析52】indicators部分代码解读(枯燥,仅供参考,源代码解析结束,后面会增加一个backtrader框架分析)
指标类里面有很多不同的指标,如果对如何使用指标做策略感兴趣的话,可以考虑阅读下相关的源码和指标的用法,就仅仅指标的源代码而言,似乎没有什么可讲的.另外,关于backtrader源代码的注释,放到网站上 ...
- overlayfs源代码解析
overlayfs源代码解析 mount挂载 注册文件系统 挂载文件系统 读写目录 openat系统调用打开目录 getdents系统调用,搜索目录 创建/删除文件 创建文件 删除文件 读写文件 读/ ...
- 历经一个月,终于搞定了SVM(支持向量机)-附源代码解析
历经一个月,终于搞定了SVM(支持向量机)-附源代码解析 前言 其实整体算下来,断断续续的也得有快两个月了(原谅博主比较笨).中间也有好几次放弃,不想写这篇总结了,但是之前立下的誓言,要将学习到的每一 ...
- Mozilla FireFox Gecko内核源代码解析(4.nsHTMLTokens)
之前我们分析了nsHTMLTokenizer(详见其解析篇),其中我们了解到了,其中设计了如何配合 nsScanner对输入流循环地解析流程,如怎么进行回溯等流式操作.实际上其中并没有包含具体的字符比 ...
- AnnaKournikova病毒源代码解析
AnnaKournikova病毒源代码解析 AnnaKournikova病毒源代码解析 本帖版权归原作者,其它网站转载须注明出处,传统媒体转载须事先与原作者和e龙西祠胡同[http://www.xic ...
- php病毒源代码,HTML_vbs病毒的简单例子源代码解析,说明:作者对某些代码进行了 - phpStudy...
vbs病毒的简单例子源代码解析 说明:作者对某些代码进行了修改.该文件是一个完整的程序.该文件执行之后,会寻找硬盘上所有满足条件的文件,对其进行强制性覆盖(满足条件的文件数据将全部丢失).并再创建一个 ...
最新文章
- DearGUI编写贪吃蛇之让蛇跑的方向受控制_最新
- 让Mac OS 10.x.x安装在Vmware虚拟机上!
- CTFshow 命令执行 web70
- wordpress安装jquery插件失败_wordpress怎么安装插件
- AndroidStudio项目提交到github
- python比较两个列表不同部分_Python实现比较两个列表(list)范围
- 微机接口技术实用教程(第2版)-任向民,王克朝,宗明魁-课后答案
- python网络爬虫系列教程——python中pyquery库应用全解
- c语言程序个位,C语言位字段
- Three.js – Building a Cube with different mater...
- BZOJ3676[APIO2014] 回文串
- 现代优化算法 之 遗传算法
- VScode 历史版本
- 从“老公”的称呼来历,看男人地位的变迁
- 前置:API:DSP:核心交换机:边界网关协议:边界:(防御)防火墙:负载均衡:摆渡机:名词解释
- svm实现非线性分类(利用smo算法)
- 小程序js实现【数字变化动画效果】
- 哈工大软件构造 复习
- 9-5日度小满金融Java研发工程师笔试
- NLP算法-关键词提取之Gensim算法库