跳至正文

WebAssembly笔记(2)-从asm.js到wasm

随着Web网页的广泛发展,拥有JIT技术加持后,JavaScript的执行效率大幅提升,但由于解释型语言的特点,以及动态类型的天生缺陷,在某些CPU密集计算型的应用场景下,JavaScript的性能仍然力不从心。而且有大量C/C++等编译型语言的软件和库,也有着搬到Web上执行的需求,但如果全部用JavaScript语言重写,显然代价十分巨大。

一系列原因催生出了WebAssembly技术的诞生,先从asm.js说起。

一 asm.js

1.1 发展历史

2011年,在Mozilla工作的Alon Zakai,想把自己以前开发的C++ 游戏跑在浏览器里,但是又不想用JavaScript重写,就想能不能把C++ 编译为JavaScript呢?于是他创建了 Emscripten 项目,用LLVM将C++编译为字节码,再将字节码编译为JavaScript,成功地将C++游戏跑在了浏览器。

当时Mozilla的CTO正是JavaScript的作者Brendan Eich,他的梦想是让Web可以运行任何应用,而Alon的项目正在实现他的梦想,于是大力支持,Emscripten成为了公司的一个正式开源项目。

但仅仅将C++编译为JavaScript还不够,因为性能不够好。主要原因是JavaScript是动态类型语言,JS引擎在生成机器码时,必须动态判断变量类型,这带来了大量的冗余代码,必然存在性能损耗。

Mozilla的JS引擎工程师Luke Wagner告诉Alon,如果Emscripten能生成特定的隐含类型的JS代码,他就可以通过优化JS引擎来提升性能,例如:

function add(x, y) {
  a = x | 0; // 参数x为整数
  b = y | 0; // 参数y为整数
  return a + b | 0; // add函数的返回值也是整数
}

通过在JS代码中增加 | 0,JS引擎就能推断出add函数的参数和返回值都是整数,从而直接编译为整数加法,提高了机器码的执行效率。对这种语法的进一步规范化,就产生了asm.js

2013年,他们把100万行C++代码的虚幻游戏引擎编译为asm.js,在浏览器中流畅的运行了3D游戏《史诗城堡》
asmjs_game

1.2 原理

asm.js并不是一种新的语言,它只是一种遵守特定规范的JavaScript,本质上还是JavaScript。它可以手工编写,但可读性较差,所以通常是由 Emscripten工具来编译生成。

它有以下两个特点。

  • 变量都是静态类型
  • 没有垃圾回收机制

前面说过,普通JS代码的执行流程是:JS源码 -> 解析器 转成 抽象语法树 -> 解释器 转为 字节码 -> 编译器 转为优化后的机器码 -> 执行。

在这过程中,由于JS的动态类型特征,同一变量上一次执行还是Object,下一次就可能变成String了,这导致JIT编译过的机器码失去作用,只能重新进行编译。asm.js 约定静态类型就避免了这种情况的发生。

针对asm.js进行优化后的JS引擎,如果发现运行的是asm.js,便可以通过AOT静态编译的方式,将代码编译成机器码(且因为是静态类型,机器码可以得到极其优化)。当JS引擎再次执行(甚至是第一次执行)这段代码时,就可以直接使用前面编译过的机器码来执行了。

通过不断的优化,测试数据表明,asm.js的性能可以达到原生C/C++代码的50%。在Firefox浏览器率先支持asm.js后,其它的Chrome、Safari、Edge等浏览器相继优化其JS引擎来执行asm.js

二 WebAssembly

2.1 发展历史

和普通JS代码相比,虽然asm.js性能提升很大,但它始终是个包含JS代码的文本,JS引擎还是需要去解析和编译,那为什么不在浏览器中增加一个虚拟机,从而能直接运行字节码呢?让越多的应用跑在Web上,并且性能越好,用户花在Web上的时间就越多,这符合各家浏览器厂商的共同利益。

因此,在2015年,各大浏览器厂商联手宣布开发WebAssembly。2017年,几大浏览器相继支持。2019年,W3C发布正式标准,WebAssembly成为继HTML、CSS、JavaScript之后的第4种Web语言。

现在C/C++、Rust、Java等越来越多的强类型编程语言,都可以编译为WebAssembly字节码,直接运行在浏览器中。就像Java字节码一样,一次编译到处运行,借助于浏览器,从而具有了跨平台特性。

2.2 原理

严格说,WebAssembly不是一种编程语言,而是一种可以在浏览器中直接运行的二进制格式,这种格式称为WASM

测试数据表明,WebAssemblyasm.js平均快了33.7%,且文件体积平均小了62.5%,另外WebAssembly在编译速度、启动速度、内存使用等方面的表现也非常好。

WebAssembly并不是要取代JavaScript,只是把更多的编程语言和应用带到Web中,且具有接近于原生的性能,是JavaScript能力的补充,使Web更加丰富和强大。

三 总结

asm.js生成的是JavaScript代码,而WebAssembly生成的是WASM格式的二进制字节码,因此WebAssembly的体积更小,运行速度更快。

asm.js的兼容性比WebAssembly好,因为它本身就是JavaScript,所有浏览器都支持asm.js的运行,当然现在主流的浏览器也都支持WebAssembly,无需担心兼容问题。知名软件AutoCAD、Google Earth都借助于WebAssembly技术,移植到了浏览器中。

WebAssembly给Web带来了更多的可能性,对于CPU密集型的应用,比如音频、视频、直播、机器学习、AR、VR、游戏等,WebAssembly既可以帮助突破性能瓶颈,也可以让其他语言的代码库得到充分利用。因此,WebAssembly的应用还刚刚开始,发展潜力巨大。

发表回复

您的电子邮箱地址不会被公开。