我们是否有必要费力创造一种通用的 Web 字节码?LLVM 就是解决方案吗?Mozilla asm.js 和 Google PNaCl 这两种支持在浏览器中运行原生代码的机制,哪种更好呢?本文汇集了网络上的一些相关观点。
ArsTechnica 上发布了一篇有关以 JavaScript 编写视频编解码器的文章, Raniz 的评论在评论区和网络上引发了激烈的讨论。Raniz 提议“在浏览器中使用一种标准化的字节码,使开发者可以在更多的语言中做出选择”,开发者可以选择他们所喜欢的 Web 编程语言,不一定使用 JavaScript。字节码可以是与 JVM 或 CLR 的字节码类似的通用平台,不过这里支持的是 Web 开发而已。这种想法乍看上去很有意思,有人甚至建议将 LLVM 的位码(bitcode)用作中间“字节码”。目前包括 ActionScript、Ada、D、Fortran、Haskell、Java 字节码、Objective-C、Python、Ruby、Rust、Scala 和 C#等多种语言都有了相应的LLVM 编译器。
位码要依赖于目标平台,这是其主要问题,也就是说,为不同架构生成的位码是不同的,这与Java 不同,因为不管面向哪种平台,Java 生成的字节码都是相同的,由JVM 针对所运行的机器生成原生代码。通用的Web 字节码还存在其他一系列问题,其中有一些也困扰着LLVM 位码(详情请参阅这里), msclrhd 在评论中指出了一些问题,下面我们节选了一部分:
将字节码标准化会给浏览器如何优化 JavaScript 代码带来一些限制……
基于什么字节码进行标准化也存在问题,因为不同的 JavaScript 引擎会使用一组不同的字节码,而且语义不同。所有引擎需要就字节码的使用达成一致。
还有一些需要注意的问题,比如不同引擎使用的字符串表示有所差别(V8/Chrome 使用的是 ASCII 字符串变体,而 Mozilla 选择的是 UTF-16),类型表示也不相同(比如 Firefox 使用了 64 位的 fatvals,其中 32 位表示值的类型,32 位表示值;64 位的 double 用到了 NaN 值的表示……)。
如果字节码是二进制的,还有大小端和浮点数表示等问题。
AlonZakai 是 Mozilla 的研究人员,主要从事 Emscripten 和 asm.js 相关的工作,他就通用的 Web 字节码写了一篇完整的博客,其中列出了实现该目标面临的一些困难:
因为各种原因,你想要这种字节码,而他想要那种字节码。有人就是偏爱某种虚拟机上的语言。但有的字节码虚拟机是专有的,或者受专利保护,或者被某家公司牢牢控制,有人就不喜欢这样的东西。因此实际上并没有哪种可以选作 Web 上通用的字节码。我们只能寄希望于某种理想的字节码,这样可选的就多了。
Zakai 也列举了这样的字节码应该满足的一些条件:
- 支持所有语言
- 高速运行代码
- 便于编译器生成
- 格式紧凑,容易转换
- 标准化
- 平台独立
- 安全
Zakai 并没有给某种满足需求新的字节码很多机会,他认为 JavaScript 就是正确的选择:“参考上面列出的 7 个条件,可以说JavaScript**** 所提供的东西已经非常接近字节码虚拟机了。”他也提到了 JavaScript 仍然存在的一些不足:
这方面 JavaScript 主要有两点不足。首先,这一点我们前面也有所提及,对有些语言的支持尚不成熟;其次,有些平台限制会影响性能,尤其是缺乏 SIMD 和共享状态的线程。
对于 SIMD 和内存可变的线程,JavaScript 能弥补其问题吗?时间会说明一切,我认为这需要花很大精力,不过我相信,标准化 JavaScript 要比标准化一种全新的字节码简单几个数量级,而且更为现实,这是很明显的。这方面引入一种字节码没有任何优势。
Zakai 又列举了创造通用虚拟机存在的更多困难,比如语言之间的类型冲突和垃圾收集问题等,之后他总结道:
因此,从技术角度讲,我认为考虑一种新的 Web 上的字节码没有多大好处。这种方法能带来的唯一明显的好处是,如果我们从头开始设计,没有历史包袱,或许会得到一个更优雅的解决方案。这种想法很吸引人,而且一般说来优雅的方案会带来更好的结果,但以前也争论过,在这一特定情况下,优雅的方案可能没有明显的技术优势,那就是为了优雅而优雅了。
尽管看上去通用字节码成功的机会并不大,但在将其他语言带向 Web 开发方面,仍然至少有两个重要的尝试。这些尝试都从 C/C++ 开始,但相关工作很容易扩展至其他语言,而且有趣的是,它们都使用了 LLVM:
- Mozilla:C/C++ –> LLVM 位码 –>Emscripten –> asm.js –> 浏览器
- Google:C/C++ –> LLVM 位码 –>PNaCl –> 浏览器
asm.js 尝试标准化能够在任何浏览器中运行的一个 JavaScript 子集,其设计便于 JavaScript 引擎优化。 Emscripten 是另一个项目,可以从 LLVM 位码生成 asm.js。据 Zakai 介绍,在Firefox 中通过asm.js 运行的C++ 代码速度是原生代码的50% ,他们预计随着时间的推移,性能会有所改进。
Google 最近宣布了 PNaCl ,InfoQ 也进行了详细地报道。该项目支持在浏览器的沙盒中运行C/C++ 代码,据 David Sehr 介绍,其速度是原生代码的 80-90%,而且还有改进空间。尽管性能比 Mozilla 的好得多,但这是有代价的:PnaCl 已经开发了两年多了。有很多相当棘手的问题需要处理,比如多种架构上的大小端、指针大小和浮点数表示存在差异。改进 Chrome 使之包含 asm.js 优化则容易得多。但另一方面,asm.js 可能会特别慢,就像 yab**uz 评论的那样:
我决不会使用 asm.js,仅仅是因为支持 asm.js 的浏览器太慢了。在最新的 Core i7-3770K 处理器上,Epic Citadel 每秒才跑 20 帧,这就是个笑话,比 Flash 播放器还慢!
JavaScript 是 Brendan Eich 在 1995 年用 10 天时间设计的,本意是成为一种客户端脚本语言,以支持向那时的静态页面中注入一些动态性。或许当时没有人会预料到,在差不多 20 年后,尽管广受批评,缺点很多,这种小语言在今天竟然有了如此重要的地位。今天 JavaScript 广泛应用于所有主流浏览器的客户端,而且,尤其是随着 Node.js 的流行,它还进入了服务器端。这并不是因为 JavaScript 设计得好,而是因为我们很难把所有的主要参与者聚到一起做出一个更好的方案,软件上的各种东西也很难切换了。和 HTTP 和 HTML 一样,尽管存在各种缺点,尽管我们都知道如果能够达成一致,我们可以做得更好,JavaScript 还是会走向繁荣。
既然我们在 JavaScript 上遇到了困难,那我们至少会有一种通用的 Web 字节码吗?我们真的需要吗?尝试在浏览器中运行其他语言编写的代码,比如用 Mozilla asm.js 或 Google PnaCl,是否有吸引力呢?asm.js 和 PnaCl 哪种方案更好?期待您的评论。
评论