CppLua

Lua源码阅读推荐顺序

Spread the love

已经用了5个月的虚幻,因为不是做业务开发,所以一般很少用到lua,所以蛮多Unreal的slua并不熟悉,打算没空的时候也读一读。

太久没用lua以至于之前读的源码都有点忘了,打算复习一下。说起阅读Lua源码,就不得不提Mike大神在raddit提出的源码阅读顺序,我也是照着这个顺序读下来的,在此暂存以备不时之需。

在今年年初的时候读完了Lua并且在源码加了不少注释:

https://github.com/vgvgvvv/ResetCore/tree/master/Note/Lua/Lua-5.1.4

 

下面开始介绍各个核心代码文件:

lmathlib.c, lstrlib.c:

get familiar with the external C API. Don’t bother with the pattern matcher though. Just the easy functions.

一些周边库,读起来非常轻松,基本就熟悉一下push、check、get之类的常用函数,读完就能用CAPI自己注册一些C++函数了。

lapi.c:

Check how the API is implemented internally. Only skim this to get a feeling for the code. Cross-reference to lua.h and luaconf.h as needed.

了解Lua API的内部实现,可以先大概看看,后续会回头进一步回来看看,lua.h和luaconfig基本是一些lua相关配置。

lobject.h:

tagged values and object representation. skim through this first. you’ll want to keep a window with this file open all the time.

Lua里面的类型,可以大概看一下,基本就可以知道Lua里面动态类型怎么实现的了。不过在看其他代码的时候也经常要回头看看。

之前写过一篇文章是关于这块的,感兴趣的同学可以看看。

Lua中动态类型的实现

lstate.h:

state objects. ditto.

lua state实现,包括全局表,字符串表都在里面,state的初始化流程,callinfo的定义也在里面。

lopcodes.h:

bytecode instruction format and opcode definitions. easy.

字节码的定义,而且能够了解每个字节码的作用,很简单,最重要的是了解字节码的储存结构。

lvm.c:

scroll down to luaV_execute, the main interpreter loop. see how all of the instructions are implemented. skip the details for now. reread later.

了解虚拟机是如何运行的,其实虚拟机就是一个循环加上嵌套递归,lua函数和c函数有些许区别,但是读起来也挺顺的。

bytecode这块之前写过一篇文章,通过工具分析lua二进制文件,感兴趣可以看一看。

反编译Lua二进制文件与Lua字节码分析

ldo.c:

calls, stacks, exceptions, coroutines. tough read.

非常重要的部分实现,包含了调用的过程,callinfo以及lua栈的结构,对理解lua的调用如何实现非常有用,如果想自己写一个语言,这块也会给你很多灵感。

异常抛出以及coroutine你会发现其实实现非常简单但是又很精妙。异常的实现实际就是c中的setjump,因为lua虚拟机里面就这几种情况,所以都能够捕获。而协程的话则是用了非常取巧的方式进行实现,和c中自己实现的协程又完全不同。

总之,看完这个文件你会学到很多东西,而且callinfo以及lua栈结构,如果你说你对lua熟悉的话这个是必须要理解的核心机制,lua的内存紧凑、鲁棒性、以及调用速度都与之有关。

lstring.c:

string interning. cute, huh?

内置的string,实际上就是维护了一个字符串表,其中比较重要的是字符串表重hash的部分,有兴趣的读者可以看看我之前发过的文章。

Lua中字符串的实现

ltable.c:

hash tables and arrays. tricky code.

luatable可以说也是lua中最精妙的部分之一,lua是如何选择使用连续结构还是散列结构?内部数据组织形式又是如何使用的?这些疑问都能够得到解答。

通常你和别人说熟悉lua,字符串与table的实现也是不得不说的两块。

ltm.c:

metamethod handling, reread all of lvm.c now.

You may want to reread lapi.c now.

对元表的处理,实际上蛮简单,元表的实现主要表现在各种地方埋点,散布在各个角落,读起来比较轻松,所以读一下C API,你会理解更深。

ldebug.c:

surprise waiting for you. abstract interpretation is used to find object names for tracebacks. does bytecode verification, too.

luadebug相关的一些代码,感兴趣的话可以读一下,我觉得倒没有前面的一些代码重要,但会对lua底层的原理理解更深,特别是callinfo链表与lua栈的构成这块。

lparser.c, lcode.c:

recursive descent parser, targetting a register-based VM. start from chunk() and work your way through. read the expression parser and the code generator parts last.

实现任何语言都逃不过的语法解析与词法解析……

想自己实现语言的可以通读一下,不然的话可能性价比低一些,lua目前用的都是自己实现的解析器,而非用工具yacc、lex之类生成的解析器,所以效率比较高,就是各种硬编码。

lgc.c:

incremental garbage collector. take your time.

Read all the other files as you see references to them. Don’t let your stack get too deep though.

If you’re done before X-Mas and understood all of it, you’re good. The information density of the code is rather high.

lua的gc,解放了C/C++程序员管理内存的压力。

可以先剧透一下,lua使用的是mark sweep垃圾回收,使用黑白灰色标记策略,牵扯到lua的数据结构到调用流程,还是比较复杂的,反正我之前就没读完。

对这块特别感兴趣的同学可以读一读,而且在最新版本的lua5.4当中对垃圾回收进行了改进,不过我没有太关注,感兴趣的同学在读完5.1之后也可以去看看最新版本lua的源码,改动应该还是非常多的。

每个版本改动都很大也可以算lua的传统了吧。

总结

阅读lua源码实际上是很享受的一个过程,你可以把握整个lua的细节,虽然很多东西平时工作用不上,但是你就是有把握全局的感觉,而且如果遇到了Lua底层bug,或者第三方库 要做接入,你就是得懂这一块。

所以我觉得游戏开发人员阅读lua源码还是性价比很高的一件事情,我阅读lua源码,除了语法分析词法分析以及GC这块,一个礼拜就读完了,回来之后感觉lua不过如此!核心源码才这么点!

不过luajit除外,我连外围函数都没读懂

打扰了!!

而且你还能发现不少Lua开发的小技巧,例如:

在阅读源码的过程中,发现strlib给空字符串添加了元表, 如下:

我们实际上可以直接通过字符串去调用string库的函数 类似于:

而我们自己也可以往其中添加方法:

有一种只有我知道的快感有没有!

 

之后想对Unity的Tolua与Unreal的SLua进行比较,这两个库实际上换汤不换药。

只不过Unity只能通过去反射来减少消耗,C#和C++透传的Wrap会带来代码体积膨胀、透传效率等问题;而Unreal因为是静态反射,可以充分享受反射带来的便利,代码量也比tolua少不少,不过不能动态反射了,灵活性上略逊一筹。

不过也是一个想法,后续写不写反正不知道,我还是要啃渲染这块,现在渲染真的是太太太太菜了……

发表评论

电子邮件地址不会被公开。 必填项已用*标注

This site uses Akismet to reduce spam. Learn how your comment data is processed.