lua.vm.js——在 JavaScript 虚拟机中运行 Lua 虚拟机

  • Abel Avram
  • 臧秀涛

2013 年 6 月 1 日

话题:JavaScript语言 & 开发架构

完整的 Lua 虚拟机不仅能在 JavaScript 虚拟机中运行,还能调用 JS 代码,Mozilla 以此显示出了 asm.js 的强大。

Alon Zakai 是 Mozilla 的研究人员,主要从事Emscriptenasm.js方面的工作。lua.vm.js是他启动的一个项目,意在显示在 JavaScript 虚拟机中运行包含垃圾回收功能的虚拟机的可能性,这里运行的是 Lua 虚拟机。Lua 虚拟机是用纯 ANSI C 编写的,所以很适合直接用 Emscripten 编译到 asm.js 中,据 Zakai 介绍,“只需对 Makefile 文件做一些小的修改”。

该项目甚至还提供了一个在浏览器中测试 Lua 的REPL。除运行 Lua 代码外,通过得到 js.global 对象,REPL 还支持调用 JavaScript 代码,与 DOM 交互,或设置回调,具体如下面的例子所示:

print('hello' .. ' ' .. 'world!') – 这是 Lua!

print(js.run('[0,1,2,3,4,5][3]')) – 在 Lua 中运行 JS

-- 使用 Lua 与页面交互

local screen = js.global.screen

print("you haz " .. (screen.width*screen.height) .. " pixels")

local window = js.global -- window 是 JS 中的 global 对象

window.alert("hello from lua!")

window.setTimeout(function() print('hello from lua callback') end, 2500)

local document = js.global.document

print("this window has title '" .. document.title .. "'")

在一个虚拟机中运行另一个虚拟机,性能是个重要的问题。据 Zakai 介绍,基准测试显示,这种情况下性能达到了原生代码的 50%,可以和其他编译到 asm.js 的 C 代码媲美,对特定场景而言已经足够好了。

有些情况下的确有太多性能问题,但也存在一些情况性能是可以接受的。特别需要记住的是,Lua 虚拟机通常比 Python 和 Ruby 等其他动态语言快得多。即使这些语言不算超快,但它们在很多场景下都有应用。

库的大小也是问题,这里库小的出奇,gzip 压缩后在 200KB 左右。

Zakai 提到,在一个虚拟机中运行另一个虚拟机,还有一些问题需要处理:

有些问题非常棘手,比如,我们无法跨虚拟机进行循环回收,如果一个 Lua 对象和一个 JavaScript 对象都没有被任何东西引用,但却彼此引用,那么要释放它们就需要能够遍历两个虚拟机中的整个堆,这样不仅这类 Lua 对象无法回收,普通的 JavaScript 对象也无法回收,基本上要用我们自己的垃圾回收来代替浏览器的处理了。出于安全和性能的原因,JavaScript 引擎不允许我们这么做。我们能做的就是让 Lua 保存指向 JavaScript 对象的强引用,在 Lua 对这样的引用进行垃圾回收时,自动释放这些 JavaScript 对象。这带来了一些限制,但重点是不要忘了,一般而言跨虚拟机进行循环回收在计算机科学中也是一个难解问题。将一个虚拟机中的对象完整地在另一个虚拟机中实现,这是唯一最简单的情况,但大部分情况下这是不可能的 (除此之外,比如有些 Lua 对象会有 finalizer,即 __gc 方法,这无法在 JavaScript 中实现) ,而且就算能实现,性能也是问题。还请注意,在 Web 浏览器中实现两个独立的虚拟机也会遇到这类问题。

Mozilla 并不像是要在浏览器中运行其他虚拟机,相反只是要显示 Emscripten 和 asm.js 的强大。Emscripten 和 asm.js 正在与 Google PNaCl 进行着面对面的竞争,这两种解决方案都试图在浏览器中运行原生代码。(更多细节请参考 InfoQ 之前的报道:“讨论:我们是否需要一种通用的 Web 字节码?”)

asm.js 和 PNaCl 还存在一个相同的问题,那就是缺乏其他浏览器的支持。Chrome 理论上可以运行 asm.js 代码,但性能相当差。比如,Lua 虚拟机基准测试在 Chrome 运行的性能小于在 Firefox 夜间构建版上运行的 30%,而 Firefox 上的性能是原生代码的 50%。正因如此,对于 Firefox 运行原生代码的这种解决方案,除非 Google 在 Chrome 中进行针对性的优化,否则没有人会在 Chrome 中运行 asm.js。而这一切都可以归结为浏览器市场份额和优化其解决方案的能力。

查看英文原文:lua.vm.js – Running Lua VM in a JavaScript VM

JavaScript语言 & 开发架构