WebAssembly和WASI介绍
1. 什么是WebAssembly
WebAssembly是一个可移植的编程目标(compilation target),它最早是运行在浏览器中的,用于解决JavaScript带来的性能问题。
1.1. JavaScript的性能瓶颈
下图为Microsoft Edge的JavaScript引擎Chakra的结构:
(图片来自:https://adtmag.com/articles/2015/12/07/microsoft-open-source-chakra.aspx?m=1)
可以看到:
- JavaScript源代码被下载下来,通过Parser转换成AST(Abstract Syntax Tree,抽象语法树);
- AST被Bytecode Generator转成字节码(中间状态的二进制码,包含执行程序,由一系列指令、程序和数据片段组成);
- 字节码进入解释器(Interpreter),解释器会将字节码翻译成机器码(计算机可以直接执行的代码,只有0和1),并执行。
关于编译器和解释器
以Java为例,Java源文件经编译器编译后,会生成可在Java虚拟机(JVM)上运行的字节码(.class
文件)。Java虚拟机,即解释器,在执行字节码时,会把字节码翻译成它所在平台可运行的机器码。
编译器:把源代码转换成更低级的代码(如二进制码、机器码)文件,但不会执行。
优点:
(1)循环内的代码在编译后可以运行很快,不需要每轮循环都解释一遍。
(2)可以做优化(compiler has more time to look at the code and make edits to it so that it will run faster)。相比之下解释器是在运行时做解释的工作,没有时间做这样的优化。
缺点:起步慢,因为要经历整个编译过程。
解释器:直接生成可让计算机硬件执行的机器码,并执行。
优点:起步快,运行代码时不需要经历整个编译的过程。
缺点:同一段代码可能被多次解释,如执行while循环时,循环内的代码在每个循环都要重新解释一次。
JIT Compiler:Just-in-time Compiler,即时编译器,是能把字节码转换成可被计算机直接执行的机器码的程序。
- JavaScript Engine中添加了一个monitor(或者叫Profiler),会在程序运行时监控代码被执行了多少次、都使用了什么类型。
- 如果一段代码被执行了很多次,就会被打上
Hot
标签,然后做一些优化。这些优化可以理解为在编译时做一些合理的假设,然后基于假设将代码提前编译好。 - 具体来说:
- 由于JavaScript是动态类型语言,在运行的时候才会知道数据真正的类型,所以在编译时只能靠概率去猜它使用的到底是什么类型,即“假设”它会使用某种类型的数据
- JIT将这种假设情况下的代码编译好,下次调用这段被打上
Hot
标签的代码时,直接将编译好的代码取过来 - 在执行前会做类型检查,看假设是否成立。成立的话,就可以直接运行已经编译好的代码;不成立的话,经优化过的代码会被舍弃,然后重新进入Interpreter进行解释(上图中的Bailout过程)
asm.js
用强制静态类型来解决这个问题,但仍需要经历耗时很长的Parser、Bytecode Generator两个单元,因此WebAssembly诞生了。
1.2. WebAssembly
WebAssembly是编程语言(如C/C++/Rust等)的编译目标,特点:(来自:https://webassembly.org)
- Efficient and fast
- aims to execute at native speed
- Safe
- describes a memory-safe, sandboxed execution environment
- Open and debuggable
- pretty-printed in a textual format
- Part of the open web platform
- be able to call into and out of the JavaScript context and access browser functionality through the same Web APIs accessible from JavaScript.
总的来说,WebAssembly的优势是:
- Fast:可以重用C/C++写好的代码,并提供接近C/C++的运行速度(接近native的执行效率)
- Safe:沙盒环境
- Portable:可移植性
2. 什么是WASI
我们前面介绍了WebAssembly之所以出现,是为了解决浏览器环境下JavaScript的性能问题。但一些开发者并不满足于此,他们希望WebAssembly不单能运行在浏览器中,还可以被推广到非浏览器环境下。
想要在非浏览器环境下运行WebAssembly,就需要解决WebAssembly与操作系统之间的通信问题。若要使WebAssembly能够在不同的操作系统上运行,即满足可移植性(Portability),就需要一套标准的系统接口,所有希望运行WebAssembly的平台只要实现了这些接口,就可以运行WebAssembly。另外,这套接口还应该保持WebAssembly的安全性(Security)原则。
基于这些需求,WASI诞生了。
WASI是WebAssembly System Interface的缩写,是一套支持WebAssembly跨设备、跨操作系统运行的系统接口,它的目的是让WebAssembly可以在非浏览器环境下运行,同时保持WebAssembly的两个主要原则:Portability和Security。
目前,实现了WASI的典型运行时(runtimes)有:
- wasmtime:Mozilla’s WebAssembly runtime
- Lucet:Fastly’s WebAssembly runtime
- a browser polyfill
2.1. 目前在主流引擎中支持的WebAssembly特性 (2022-07-21)
来源:https://webassembly.org/roadmap/
After the initial release, WebAssembly has been gaining new features through the standardization process. For the complete list of current proposals and their respective stages, check out the WebAssembly/proposals repo.
The table below aims to track implemented features in popular engines:
参考资料
[1] A crash course in just-in-time (JIT) compilers:https://hacks.mozilla.org/2017/02/a-crash-course-in-just-in-time-jit-compilers/
[2] 你知道「编译」与「解释」的区别吗?:https://huang-jerryc.com/2016/11/20/do-you-konw-the-different-between-compiler-and-interpreter/
[3] WebAssembly完全入门——了解wasm的前世今身:https://zhuanlan.zhihu.com/p/68048524
[4] JavaScript 编译 - JIT (just-in-time) compiler 是怎么工作的:https://zhuanlan.zhihu.com/p/99395691
[5] Standardizing WASI: A system interface to run WebAssembly outside the web:https://hacks.mozilla.org/2019/03/standardizing-wasi-a-webassembly-system-interface/
[6] Roadmap: https://webassembly.org/roadmap/