最近想试一下, Lua JIT 2.0 能给我们的系统带来多大的提升。但可惜的是,我们一开始就在用 Lua 5.2 来构建系统,而 Lua JIT 2.0 只支持 Lua 5.1 的 API ,在可以看到的时间里,恐怕也不太会去支持 5.2 了。
所以,我只能想办法反向支持 Lua 5.1 。
语法层面最重大的改变是 Lua 5.2 取消了环境表这个概念,转而提供 _ENV 这个语法糖。
许多小细节是 C API 上的变化。这使得按 Lua 5.2 标准写的 C 库,无法在 Lua 5.1 环境下编译。我打算用 Lua 5.1 的 API 来模拟出来。
我并没有完全实现所有 Lua 5.2 新增的 API ,比如对 continuation function 的支持,几乎不可能在 Lua 5.1 已有的 API 上完成的。
一些简单的 API 的实现我 。
luaL_checkversion 很有用,但很难完全实现其功能。无法检测出重复链接。
lua_arith 虽然可以实现,但是直接用 5.1 的 API 模拟出来,会比较繁琐,性能低下。而我也没用它,所以就放弃了。
lua_upvalueid 和 lua_upvaluejoin 估计也不太会用的上。
luaL_Buffer 在 Lua 5.2 里结构变了,所以,新增加的 luaL_buffinitsize 和 luaL_prepbuffsize 是无法实现相同的语义的,不想改变 5.1 里的 auxlib 的行为,所以只能回避用它们了。
对于 lua 层面的 API ,改变最大的是 load 的语义。这是和 _ENV 一起改变的,完美支持会比较麻烦。我先。
一开始,我想通过修改用户传入的代码,在前面增加一小段代码来模拟 _ENV 的行为。后来发现,我们自己用的库里有一部分是用 binary 格式来在 State 间传递 function 的。而二进制模式的代码,不能通过附加文本代码的方式来改变行为。这个难题下一步再去解决。
Lua 5.2 里的 string.format 中,%s 会默认调用对象的 __tostring 方法,而 5.1 则不会。我不打算更新 5.1 中的 format 方法,还是把 lua 代码中的 format 参数显式调用一下好了。那些地方多是用来输出 log 的,只要避免将 nil 传进入就可以了。
Lua 5.2 改进了 coroutine 的支持,好在 Lua JIT 2.0 也同样支持了。但是 Lua JIT 2 似乎对 __pairs 的支持(默认关闭)是有 bug 的。今天调试了很久终于确认并非我们自己代码的 bug 。
我构造了一个简单的 test case :
local tbl = {} local a = { values= { foo = 1 } } local iter = function(value) local function loop(t,k) return next(t,k) end return loop, value end local mt = { __pairs = function(self) local values = rawget(self, "values") return iter(values) end } setmetatable(a,mt) tbl.a = a local function trav(k,t) if type(t) == "table" then print(k, t) for k,v in pairs(t) do trav(k,v) end end end trav("",tbl)在 luajit 2.0 下运行,会输出两个 a :
table: 0x00327fa8 a table: 0x00321d00 a table: 0x00321d00a 这个字段被重复迭代了两次。
今天还发现,debug 库中的 getinfo 信息,lua 5.2 比 lua 5.1 更丰富。5.2 用 nparams 字段,可以取得函数的参数个数。而 5.1 里把参数和 local 变量一视同仁。
在旧代码里,我们试图这样去取得一个函数的参数名字(为了匹配通讯协议)。
local nparam = debug.getinfo(f,"u").nparams local p = {} for i=1,nparam do local name = debug.getlocal(f,i) table.insert(p, name) end在 Lua 5.1 里,是没有 nparams 字段的。而且 getinfo 不能传入一个函数,而必须是一个堆栈层次数。我只好使用了一个变通的方案来达到相同的功能。
local function gen_hook(p) return function() local i = 1 while true do local name = debug.getlocal(2,i) if name == nil or string.byte(name) == 40 then -- '(' is 40 break end p[i] = name i = i + 1 end error() end end function debug.params(f) local p = {} local co local function probe() debug.sethook(co, gen_hook(p), "c") f() end co = coroutine.create(probe) coroutine.resume(co) return p end
还在用5.1.4。。不敢切换5.2,更别提jit了
Posted by: ctemple | (8) September 14, 2012 06:25 PM
lua5.1移植到luajit2的兼容性问题,有没有大大说说啊,用了luajit2有一次怪异的宕机,也没解决。
Posted by: Anonymous | (7) September 14, 2012 06:00 PM
@ST 不晓得你说的LuaJIT2在生产环境不靠谱是指哪方面,从lua5.1移植到luajit2是有点儿兼容性问题必须解决,但是我们现在就是用于生产环境的。
Posted by: bbp | (6) September 13, 2012 07:33 PM
@ST 听到这个消息,我感到万分悲痛。
@Cloud 为啥不直接用 5.1 呢
Posted by: pass86 | (5) September 13, 2012 12:30 PM
@zhouzuoji
Lua 5.2 的 _ENV 是去掉 5.1 的"环境"这个语言核心特性, 用一个语法糖来兼容.
这是在做减法.
Posted by: Cloud | (4) September 13, 2012 10:11 AM
上面想说的是弊大于利:)
Posted by: zhouzuoji | (3) September 13, 2012 09:01 AM
云风一直在倒腾不同的语言工具不同的版本,感觉完全没有必要。选择最适合自己的一个稳定版本就行了。现在很多互联网服务器跑的还是古老的unix和linux发行版呢。引入太多语法糖比多写几行代码,显然利大于弊。
Posted by: zhouzuoji | (2) September 13, 2012 08:58 AM
LuaJIT在生产环境感觉很不靠谱. 之前尝试把项目转到LuaJIT, 发现了几处崩溃. 尽力解决掉一部分, 但后来经过评估, 还是没敢上.
--------------------------------------------------------------------------
--------------------------------------------------------------------------
8.1 – Changes in the Language
·Environment的概念变化了。仅Lua函数具有environment。要设置Lua函数的environment,请使用变量_ENV,或者使用函数。
C函数不再有environment。如果你希望在几个C函数之间共享状态,请使用upvalue作为一个共享表。(你可以使用打开一个C库,并在所有函数之间共享同一upvalue)。
为了操作userdata(5.2中称为user value)的"environment",使用新的函数和。
·Lua标识符不能使用区域相关的字符(换言之,不能使用中文作为标识符了)
·若垃圾回收器已停止,那么做一步回收动作,或做一次完全回收动作,都不会重启垃圾回收器(换言之,你需要先显式的启动它)。
·弱表和弱键现在按短暂表(Ephemeron table)处理。
·tail return事件在debug hook中被移除了。替换的办法是,尾调用生成一个特殊的新事件,tail call,因此debugger能够知道不会有对应的返回事件。
·函数值之间的相等判定发生改变。现在,一个函数定义不一定创建一个新值,它可能重用以前的值——当旧值与新函数没有明显的不同的时候。
------------------------------------------------------------------------
------------------------------------------------------------------------