没想到 Lua 的作者理论水平这么高,这篇文章读的我顿生高屋建瓴之感。云风分享了一篇中译:http://www.codingnow.com/2000/download/The%20Implementation%20of%20Lua5.0.pdf

全篇的主题有 4 个:1. 基于寄存器的虚拟机;2. 用于将 table 作为数组使用的新算法;3. 闭包的实现;4. 以及协程。第二点我关注不多,会写的比较简略。

1 简介

简介主要就是说,我们搞 Lua 嘛,就是一个实验室出来的产品,没想到今天在工业界特别是游戏界红得发紫,这主要是得益于 Lua 轻灵小巧,注重可移植性。除了上面提到的 4 点,这篇文章还有一些铺垫的章节,帮助你们理解我们这个牛逼哄哄的东西。(这些铺垫的东东也很牛逼,建议参考中译)

2 Lua 的设计和实现

我们写的 Lua 简洁,高效,可移植,非常容易嵌入。

3 Lua 的类型系统

这段看代码比较简洁:

typedef struct {
   int t;
  Value v; 
} TObject;

typedef union {
  GCObject *gc;
  void *p;
  lua_Number n;
  int b;
} Value;

作者顺便扯了一下对象的装箱拆箱,嘲笑 python 的实现比 Lua 要慢。

4 Lua 的 Table

牛逼的地方在于,如果 table 是当 array 用,数字的 key 比较紧凑,我们就会拿一个真实的数组去储存它,即省空间又快速,如果是当成单纯的关联组来用,那么数组部分则不会分配,避免浪费

5 函数和闭包的实现

闭包在 lua 里应用得非常广泛。每一个函数都会被编译成一个 prototype 作为原型。实际执行的时候,则会为其生成一个闭包,包含了对函数原型的引用,对全局变量的引用表,以及对 upvalue 的引用(用来访问外部的局部变量)。

以函数为第一类对象,以及带词法作用域的语言,大多会遇到外部局部变量访问的问题。考虑下面的例子:

function add(x)
    return function(y)
                   return x + y
               end
end

add2 = add(2)
print(add2(5))

当调用 add2 的时候,add 函数已经返回,那么 add2 函数体内的 x 会不会随着 add 函数的退栈而被销毁呢?如果不被销毁,又应该如何保存这个变量呢?

Lua 巧妙的使用了 upvalue 解决这一问题,参考下图:

每当创建一个新闭包,Lua 就会检查外部定义的局部变量是否有加入 upvalue 链表,如果没有就创建一个 upvalue 加入双向链表里。所有对外部定义的局部变量访问,都是通过 upvalue 的指针进行间接访问的。当外部函数退出时,因为函数退栈,局部变量被清理,这时候局部变量就会被转存在 upvalue 的值域里,然后把 upvalue 的指针指向自身的值域。对于定义局部变量的函数,这些局部变量还是栈上的元素,不许通过 upvalue 访问。

对于多层函数嵌套的情况,当一个函数需要访问的变量不在上一层函数的局部变量,就访问上一层函数的闭包。闭包具有传递性,会由外部函数传递到内部。

下篇:The implementation of Lua 5.0 阅读笔记(二)