asm.js
asm.js是一个中間語言,设计目的是使采用C等编程语言编写的计算机软件可运行为网络应用程序,同时性能特征明显优于标准JavaScript。
設計者 | Mozilla |
---|---|
2013年3月21日[1] | |
操作系统 | 平台无关 |
網站 | asmjs |
啟發語言 | |
JavaScript |
asm.js包括一个JavaScript的严格子集,其中的代码采用具有手动内存管理的静态类型语言(就像C语言)编写,代码使用一个源代码至源代码编译器(例如基于LLVM的Emscripten)翻译。通过将语言特性限制在适合提前优化和其他性能改进的范围内,性能得到了提高。
Mozilla Firefox是第一个实现针对asm.js优化的浏览器,从Firefox 22开始使用。[2]
设计
asm.js由JavaScript语言的一个严格子集组成。它可以显著提高采用具有手动内存管理(例如C)的静态类型语言编写的网络应用程序在使用源代码至源代码编译器转换为JavaScript后的性能。Asm.js的目标并不是提高手写JavaScript代码的性能,也不实现增强性能以外的其他目的。
通过将语言特性限制在适合提前优化和其他性能改进的范围内,其旨在具有比标准JavaScript更接近于本地(原生)代码的性能特征。[3]通过使用JavaScript的一个子集,asm.js很大程度上支持所有主要的网页浏览器[4],这不同于WebAssembly或Google Native Client等途径。
代码生成
asm.js通常不直接编写,而是作为一种通过编译器生成的中间语言,该编译器获取C++或其他语言的源代码,然后输出asm.js。
例如,提供下列C语言代码:
int f(int i) {
return i + 1;
}
Emscripten将输出下列JavaScript代码:
function f(i) {
i = i|0;
return (i + 1)|0;
}
注意新增的|0
和去除的类型说明符。在JavaScript中,按位运算符会将操作数转换为32位有符号整数并给出整数结果。这意味着使用0的按位OR为一个无作用的操作,只是将值转换为整数。通过对每个参数这样做,确保了从外部代码调用该函数时,该值被转换为正确的类型。这也用于返回值,在该情况下确保添加1到i的结果将是一个整数(否则可能变得太大),并标记函数的返回类型。这些转换为asm.js所必需,这样优化编译器才可以提前生成高效的本地代码。在此类优化编译器中,当asm.js代码调用其他asm.js代码时,转换不执行,因为必需的类型说明符意味着已保证值具有正确的类型。此外,不同于执行浮点加法和转换为整数,它可以简单地执行本机整数运算。这样一来,它可以得到显著的性能增益。
下面是另一个计算字符串长度的例子:
size_t strlen(char *ptr) {
char *curr = ptr;
while (*curr != 0) {
curr++;
}
return (curr - ptr);
}
它对应以下asm.js代码:
function strlen(ptr) {
ptr = ptr|0;
var curr = 0;
curr = ptr;
while (MEM8[curr]|0 != 0) {
curr = (curr + 1)|0;
}
return (curr - ptr)|0;
}
在生成的代码中,变量MEM8实际上是一个类型缓冲区的逐字节“视图”,它充当asm.js代码的堆(heap)。
性能
因为asm.js在浏览器中运行,所以性能很大程度上取决于浏览器和硬件。编译为asm.js的C程序的初步基准通常比使用Clang的本地编译慢一倍以上。[5]
这种超过普通JavaScript的性能增益主要是由于100%的类型一致性以及几乎没有垃圾回收(内存是手动管理的大型类型数组)。这个更简单的模型没有动态行为,没有内存分配或释放,只有一组简单、定义明确的整数和浮点操作,从而可实现更好的性能和优化潜力。
Mozilla在2013年12月的基准测试显示:“使用float32优化的Firefox可以运行所有基准,只比原生速度慢不到1.5倍。[6] Mozilla指出本地编译代码的性能不是单个度量,而是一个范围,使用不同的本地编译器(此例中为Clang与GCC)将提供不同性能的代码。“事实上,在一些基准测试比如Box2D、FASTA和copy中,asm.js与Clang比较接近,或者比Clang到GCC还接近Clang。在一种情况下,asm.js甚至在Box2D上略微击败Clang。”
实现
Emscripten项目提供了可以编译C和C++(或其他任何可转换为LLVM IR的语言)代码为asm.js的工具。[7]
所有支持JavaScript较新版本的浏览器都应该能支持运行asm.js代码,因为它是该规范的子集。
部分浏览器的实现针对asm.js进行了特别优化:
- Mozilla Firefox是第一个实现针对asm.js优化的网页浏览器,自Firefox 22开始使用。 OdinMonkey是Mozilla在Firefox中使用的asm.js提前编译器,它是IonMonkey(SpiderMonkey的JIT编译器)的一个组件。
- 微软在Microsoft Edge使用的JavaScript引擎Chakra中实现了asm.js支持,执行验证以产生高度优化的JIT代码。[8]
- Google Chrome的V8 JavaScript引擎在Chrome 28中对asm.js基准测试的性能是以前Chrome版本的两倍以上,[9]尽管Chrome的V8没有使用提前编译。
采用
目前几乎所有基于asm.js的应用程序都是使用Emscripten或Mandreel编译为asm.js的C/C++应用程序。
到目前为止,已有不少编程语言、应用程序框架、程序、函式庫、游戏、游戏引擎及其他软件已被移植。[10]部分名单见下:
编程语言
程序和库
游戏
数学计算
- HTML5 Fractal Playground[38] – 绘制迭代函数生成的分形,例如Mandelbrot fractal。
参见
- WebAssembly – 一个开发中的用于浏览器的字节码,旨在比asm.js更快地解析
RPython - CrossBridge
- Google Native Client(NaCl)
参考资料
- . Luke Wagner's blog. 21 Mar 2013 [13 Nov 2014]. (原始内容存档于2017-04-21).
- . Mozilla. [July 4, 2013]. (原始内容存档于2014-08-21).
- . Asm.js. [2015-03-05]. (原始内容存档于2015-03-06).
- . Asmjs.org. July 26, 2014 [2017-03-15]. (原始内容存档于2014-06-04).
- . Asm.js. [2015-03-05]. (原始内容存档于2014-06-04).
- Alon Zakai; Robert Nyman. . 20 December 2013 [11 April 2014]. (原始内容存档于2017-03-31).
- . Github.com. [2015-03-05]. (原始内容存档于2015-03-03).
- . Microsoft. May 7, 2015 [May 7, 2015]. (原始内容存档于2017-03-31).
- . Google. [2013-07-06]. (原始内容存档于2016-09-15).
- . [2017-03-15]. (原始内容存档于2017-03-20).
- . Kripken.github.io. [2015-03-05]. (原始内容存档于2015-02-17).
- . Themucker.github.io. [2015-03-05]. (原始内容存档于2014-06-15).
- . Repl.it. [2015-03-05]. (原始内容存档于2015-03-06).
- . Repl.it. [2015-03-05]. (原始内容存档于2015-03-03).
- . Trypepperjs.appspot.com. [2015-03-05]. (原始内容存档于2020-02-14).
- . Vps.etotheipiplusone.com. [2015-03-05]. (原始内容存档于2015-02-13).
- . [2017-03-15]. (原始内容存档于2017-03-16).
- . Coolwanglu.github.io. [2015-03-05]. (原始内容存档于2017-10-19).
- . [2017-03-15]. (原始内容存档于2012-10-12).
- . Github.com. [2015-03-05]. (原始内容存档于2015-02-16).
- . Manuuels.github.io. [2015-03-05]. (原始内容存档于2015-04-25).
- . Github.com. [2015-03-05]. (原始内容存档于2019-02-15).
- . Gnuplot.respawned.com. [2015-03-05]. (原始内容存档于2015-02-22).
- . Github.com. [2015-03-05]. (原始内容存档于2015-02-22).
- . Github.com. [2015-03-05]. (原始内容存档于2014-12-05).
- . UnrealEngine.com (新闻稿). May 2, 2013 [2017-03-15]. (原始内容存档于2016-11-30).
- . ExtremeTech. Ziff Davis. [2015-03-05]. (原始内容存档于2015-03-10).
- . Blogs.unity3d.com. April 29, 2014 [2017-03-15]. (原始内容存档于2014-07-27).
- . Clb.demon.fi. [2015-03-05]. (原始内容存档于2015-03-06).
- . godotengine.org. November 10, 2016 [2017-03-15]. (原始内容存档于2017-01-13).
- . Kripken.github.io. [2015-03-05]. (原始内容存档于2015-02-23).
- . Forandom.github.io. [2015-03-05]. (原始内容存档于2015-03-15).
- Guryanov Aleksander. . Epicport. [2015-03-05]. (原始内容存档于2015-03-10).
- . Developer.mozilla.org. [2015-03-05]. (原始内容存档于2015-03-04).
- . Ars Technica. 15 Oct 2014 [15 Oct 2014]. (原始内容存档于2014-10-16).
- . [2015-04-09]. (原始内容存档于2015-03-29).
- . Jsmess.textfiles.com. [2015-03-05]. (原始内容存档于2015-03-05).
- . Danielsadvernture.info. [2015-03-05]. (原始内容存档于2015-02-22).
外部链接
- 官方网站
- GitHub上的asm.js頁面
- Asm.js: The JavaScript Compile Target(页面存档备份,存于)
- RPerl(页面存档备份,存于)
- Asm.js usage per Google Chrome statistics(页面存档备份,存于)