初识Luajit
转自:http://www.cppblog.com/pwq1989/archive/2013/11/28/204487.html
大家可以从官网下载到源码(http://luajit.org/),也可以从Github(https://github.com/LuaDist/luajit)down下来,顺便还可以看下commit记录。
大家对着luajit的wiki结合源码看的话会更好些,因为。。文档太特么少了!!
目录结构:
-- src
-- host
-- jit
*.c
*.h
*.dasc
等等,别的不是很重要
最开始我是从main函数开始看的,然后。。碰了一鼻子灰,后来研究下他的makefile,发现他是这样子的编译的,贴一下关键的msvcbuild.bat的代码(这个更容易看懂)
:X64
minilua %DASM% -LN %DASMFLAGS% -o host\buildvm_arch.h vm_x86.dasc
@if errorlevel goto :BAD %LJCOMPILE% /I "." /I %DASMDIR% host\buildvm*.c
@if errorlevel goto :BAD
%LJLINK% /out:buildvm.exe buildvm*.obj
@if errorlevel goto :BAD
if exist buildvm.exe.manifest^
%LJMT% -manifest buildvm.exe.manifest -outputresource:buildvm.exe buildvm -m peobj -o lj_vm.obj
@if errorlevel goto :BAD
buildvm -m bcdef -o lj_bcdef.h %ALL_LIB%
@if errorlevel goto :BAD
buildvm -m ffdef -o lj_ffdef.h %ALL_LIB%
@if errorlevel goto :BAD
buildvm -m libdef -o lj_libdef.h %ALL_LIB%
@if errorlevel goto :BAD
buildvm -m recdef -o lj_recdef.h %ALL_LIB%
@if errorlevel goto :BAD
buildvm -m vmdef -o jit\vmdef.lua %ALL_LIB%
@if errorlevel goto :BAD
buildvm -m folddef -o lj_folddef.h lj_opt_fold.c
@if errorlevel goto :BAD
先创建了一个buildvm.exe的中间工具,来自动生成代码,分别生成了lj_vm.obj,lj_bcdef.h,lj_ffdef.h ,lj_recdef.h ,jit\vmdef.lua,lj_folddef.h, lj_libdef.h
其中lv_vm.obj是依赖于host\buildvm_arch.h的,这个是用DynASM预处理vm_x86.dasc生成的,这个工具的具体分析会在下一篇博客提及。
先来看下上面自动生成的代码:
lj_bcdef.h:
LJ_DATADEF const uint16_t lj_bc_ofs[] = {
,
,
,
,
, }; LJ_DATADEF const uint16_t lj_bc_mode[] = {
BCDEF(BCMODE)
BCMODE_FF,
BCMODE_FF,
BCMODE_FF,
BCMODE_FF,
BCMODE_FF, };
lj_bc_ofs[]可能是bc在vm代码段中的偏移量(这个我还没深入进去调试一下),vm的一部分是用DynASM直接撸汇编撸出来的,wiki中也有提到下一步jit化的opcode等等。
#define BCMODE(name, ma, mb, mc, mm) \
(BCM##ma|(BCM##mb<<)|(BCM##mc<<)|(MM_##mm<<)),
#define BCMODE_FF 0 #define BCDEF(_) \
/* Comparison ops. ORDER OPR. */ \
_(ISLT, var, ___, var, lt) \
_(ISGE, var, ___, var, lt) \
_(ISLE, var, ___, var, le) \
_(ISGT, var, ___, var, le) \
...
lj_ffdef.h:
FFDEF(assert)
FFDEF(type)
FFDEF(next)
FFDEF(pairs)
FFDEF(ipairs_aux)
...
FFDEF的定义是在
/* Fast function ID. */
typedef enum {
FF_LUA_ = FF_LUA, /* Lua function (must be ). */
FF_C_ = FF_C, /* Regular C function (must be ). */
#define FFDEF(name) FF_##name,
#include "lj_ffdef.h"
FF__MAX
} FastFunc;
差不多就是用FF_##name把上面的名字拼接起来,然后生成在enum里面,这样就能当成是数字,在数组中迅速找到入口了
vmdef.lua:
这个里面内容就不贴了,包括bcname,irname,irfpm,irfield,ircall 的定义,在jit文件夹下面,用于调试等,比如在dump.lua中就有用到
local jit = require("jit")
assert(jit.version_num == , "LuaJIT core/library version mismatch")
local jutil = require("jit.util")
local vmdef = require("jit.vmdef") // ← ← ← ←
当你用luajit -jdump的时候,就是调用的lua的jit库里面的lua函数
lj_recdef.h:
static const uint16_t recff_idmap[] = {
,
0x0100,
0x0200,
0x0300,
,
,
0x0400, }; static const RecordFunc recff_func[] = {
recff_nyi,
recff_c,
recff_assert,
recff_type,
recff_ipairs_aux, };
其中recff_func[]是被注册的被traced jit 跟踪的函数,具体可是在lj_ffrecord.c里面看到
recff_idmap[]被用在lj_ffrecord_func这个函数中,有一个关键的数据结构RecordFFData,用来记录在trace过程中被调用函数的参数和返回值个数,和一些辅助数据,opcode,literal等等。通过recff_idmap[]保存的值来区分函数(待仔细研究)
lj_folddef.h:
static const FoldFunc fold_func[] = {
fold_kfold_numarith,
fold_kfold_ldexp,
fold_kfold_fpmath,
fold_kfold_numpow, }; static const uint32_t fold_hash[] = {
0xffffffff,
0xffffffff,
0x5b4c8016, };
用在FOLD optimization中,见lj_opt_fold.c,主要在
if ((fh & 0xffffff) == k || (fh = fold_hash[h+], (fh & 0xffffff) == k)) {
ref = (IRRef)tref_ref(fold_func[fh >> ](J));
if (ref != NEXTFOLD)
break;
}
是根据数组偏移获取函数,直接执行。
(这个Optimation略复杂,以后的博文中再说)
----------------------------------------分割线-------------------------------------------
以上就是buildvm生成代码,在很多.c的文件中,他加入了一些无意义的MARCO,目的是为了能被buildvm识别出
下面说说src根目录下面的文件:
lauxlib.h:
用户开发扩展和与C交互的时候的头文件
lib_*.h /.c:
顾名思义,就是利用LuaAPI写的内部标准库,会在方法上表明是否会被trace ( LJLIB_REC(.) )。
ljamalg.c:
文件的合并
lj_alloc.h /.c:
定制的Memory Allocator
lj_api.c:
lj_arch.h:
lj_jit.h:
jit编译器里面数据结构的定义
lj_asm.h/ .c lj_asm_*.c lj_emit_*.h lj_target_*.h/.c :
将IR编译成Machine Code,关键的数据结构ASMState,线性扫描的O(n2)分配算法
lj_bc.h/ .c:
Luajit字节码的定义和内存布局
lj_bcdump.c lj_bcread.c lj_bcwrite.c:
围绕着字节码的操作
lj_carith.c:
lj_ccall.h/ .c lj_ccallback.h / .c :
FFI C语言函数调用和回调绑定
lj_debug.h/.c :
调试与自省用
lj_def.h:
这个很重要,重要的类型和一些宏定义在这里
lj_c*.h/ .c:
和C语言先关的,比如类型转化,char管理,数据管理
lj_frame.h:
Luajit的栈帧管理
lj_func.h/.c:
Function handle和闭包有关的upvalue数据结构
lj_gc.h/.c:
GC相关,GC可以看下luajit的wiki,里面涉及不少增量式GC的paper和作者的看法
lj_gdbjit.h/.c :
对gdb的支持
lj_ir*.h/.c:
SSA,IR相关(这个和bytecode还是不一样的)操作和优化
lj_lex.h/.c lj_parse.h/.c:
lexer和parser
lj_mcode.h/.c:
Machine Code管理
lj_opt_*.h:
各种bytecode层面上的优化
lj_snap.h/.c:
快照支持
lj_state.h/.c:
LuaState和Stack的操作
lj_str*.h/.c lj_tab.h/.c:
原生类型string和table操作
lj_udata.h/.c:
类型user data的操作
lj_vm.h/.c lj_vmevent.h/.c:
vm的API和事件注册(lj_vmevent_send)
lj_vmmath.h/.c:
对vm支持的math库
lua.h:
luaState等基本的Lua结构
lualib.h:
和Lua一样,标准库的API
luajit.h:
luajit 的public API
vm_*.dasc:
编译期被DynASM预处理的源文件,下一篇讲DynASM时候介绍dasc文件
wmain.c:
windows下面的main入口
和Trace相关的:
lj_crecord.h/.c : C操作的trace record
lj_dispatch.h/.c : 指令分发,调用ASMFuction,处理指令前的hook和记录trace用的hot count,有一个重要的数据结构 GG_State
lj_ff*.h/.c: 上面讲lj_ffdef.h的时候提过,trace的时候 记录Fast Function的调用记数
lj_trace.h/.c: trace的具体过程
lj_traceerr.h : trace error
初识Luajit的更多相关文章
- Android动画效果之初识Property Animation(属性动画)
前言: 前面两篇介绍了Android的Tween Animation(补间动画) Android动画效果之Tween Animation(补间动画).Frame Animation(逐帧动画)Andr ...
- 初识Hadoop
第一部分: 初识Hadoop 一. 谁说大象不能跳舞 业务数据越来越多,用关系型数据库来存储和处理数据越来越感觉吃力,一个查询或者一个导出,要执行很长 ...
- python学习笔记(基础四:模块初识、pyc和PyCodeObject是什么)
一.模块初识(一) 模块,也叫库.库有标准库第三方库. 注意事项:文件名不能和导入的模块名相同 1. sys模块 import sys print(sys.path) #打印环境变量 print(sy ...
- 初识IOS,Label控件的应用。
初识IOS,Label控件的应用. // // ViewController.m // Gua.test // // Created by 郭美男 on 16/5/31. // Copyright © ...
- UI篇(初识君面)
我们的APP要想吸引用户,就要把UI(脸蛋)搞漂亮一点.毕竟好的外貌是增进人际关系的第一步,我们程序员看到一个APP时,第一眼就是看这个软件的功能,不去关心界面是否漂亮,看到好的程序会说"我 ...
- Python导出Excel为Lua/Json/Xml实例教程(一):初识Python
Python导出Excel为Lua/Json/Xml实例教程(一):初识Python 相关链接: Python导出Excel为Lua/Json/Xml实例教程(一):初识Python Python导出 ...
- 初识SpringMvc
初识SpringMvc springMvc简介:SpringMVC也叫Spring Web mvc,属于表现层的框架.Spring MVC是Spring框架的一部分,是在Spring3.0后发布的 s ...
- 初识redis数据类型
初识redis数据类型 1.String(字符串) string是redis最基本的类型,一个key对应一个value. string类型是二进制安全的.意思是redis的string可以包含任何数据 ...
- Redis初识、设计思想与一些学习资源推荐
一.Redis简介 1.什么是Redis Redis 是一个开源的使用ANSI C 语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value 数据库,并提供多种语言的API.从2010 年 ...
随机推荐
- PAT 1051. 复数乘法 (15)
复数可以写成(A + Bi)的常规形式,其中A是实部,B是虚部,i是虚数单位,满足i2 = -1:也可以写成极坐标下的指数形式(R*e(Pi)),其中R是复数模,P是辐角,i是虚数单位,其等价于三角形 ...
- mysql 大数据 查询方面的测试
---方法1: 直接使用数据库提供的SQL语句---语句样式: MySQL中,可用如下方法: SELECT * FROM 表名称 LIMIT M,N---适应场景: 适用于数据量较少的情况(元组百/千 ...
- Jquery定义对象( 闭包)
转自:http://www.cnblogs.com/springsnow/archive/2010/06/03/1750832.html 例一:添加对象的静态属性 声明一个对象$.problemWo, ...
- 遇到IIS configuration error错误的可以看看,不一定是权限问题
最近接手了别人的一个 DOT NET项目,编译.调试一切都OK(心里暗暗高兴),发布吧,结果放到服务器上一运行出现Configuration Error错误,提示:“Access to the pat ...
- ubuntu14.04下svn版本管理系统的安装及常用命令的使用整理
ubuntu14.04下安装svn$sudo apt-get install subversion 执行这一步就安装完成了,在ubuntu先安装很方便 安装完成后,创建版本库目录,由于是本地环境,就在 ...
- 每天一个Linux命令(28)df命令
报告文件系统磁盘空间的使用情况.获取硬盘被占用了多少空间,目前还剩下多少空间等信息. (1)用法: 用法: df [选项] [文件] (2)功能: 功能: 显示 ...
- [转]eclipse中的常用快捷键
1.选中你要加注释的区域,用ctrl+shift+C 会加上//注释2.先把你要注释的东西选中,用shit+ctrl+/ 会加上注释3.要修改在eclispe中的命令的快捷键方式我们只需进入windo ...
- AC自动机的一点理解
\(fail\)指针:指向最长的在\(tire\)里出现的后缀 比\(tire\)多出来的子边:原来的\(tire\),我们失配后又得返回根结点再次匹配,而加入这些边后只需要花\(strlen(s)\ ...
- Mac OS下新建文本文档
---恢复内容开始--- 介绍 不知道小伙伴们有没有发现这样一件事情:Mac下没有新建文本文档!如果你恰好经常需要新建类似于.cpp,.in,.out等文件的话,每次终端用一堆$ cd命令再加上一句$ ...
- 20145229吴姗珊 《Java程序设计》小总结
20145229吴姗珊 <Java程序设计>小总结 教材学习内容总结 由于今天考试考到了操作题,根本无从下手,然后才意识到原来之前的学习都是蜻蜓点水,一味的把学习建立在给老师学,为家长学的 ...