Abstract
最近参加deeplang
的的过程中,接触到了一些编译领域的新技术,总结一下希望有时间了可以进一步的深入了解。参考资料是WebAssembly标准入门。
Points
过去很多技术尝试将C/C++
程序直接运行在浏览器中,比如TypeScript
将C/C++
代码转换为JS
。
Emscripten
而这个项目利用LLVM
编译器前端编译C/C++
代码,生成LLVM
平台特有的跨平台中间语言代码,最终再将IR
转换为JavaScript
的asm.js
子集——这是WebAssembly
的基础。
AOT编译
JIT编译
JIT
的优点在于Profile-Based Optimization
,根据运行时信息然后随着时间的推移尽可能的得到最优的代码。
而AOT
的优点在于无需runtime
运行,直接静态链接至最终的程序中。
WebAssembly
JavaScript
运行在其虚拟机上,而WebAssembly
也运行在其虚拟机上。而现在Node.js 8.0
之后的版本也可以运行WebAssembly
——也就是说WebAssembly
虚拟机可以脱离JS
的环境支持,不仅仅运行在浏览器中。
WebAssembly概述
和LLVM IR
很像,有两种汇编表示——.wat
文本表示和.wasm
机器表示。
关键概念
- 模块
由.wasm
编译而来的可执行机器码的二进制对象。
- 内存
网页环境下,wasm
的内存由JavaScript
中的ArrayBuffer
对象实现的。
- 表格
引入表格对象用于存储函数引用来模拟C/C++
指针。
- 实例
- 导入对象 调用JS函数
- 导出对象 提供接口
指一个模块及其运行时的所有状态,包括内存,表格以及导入对象等。模块只有被实例化之后才可以调用。
程序生命周期
- 将
wat
或者其他语言编译成.wasm
文件 - 网页中使用
fetch
等获取.wasm
文件emrun --no_browser --port 8080 .
将文件运行在http
协议上- 然后打开
http://localhost:8080/xxx.html
- 将
.wasm
编译为模块,编译过程中进行合法性检查 - 实例化,初始化导入对象,创建模块实例
- 执行实例的导出函数,完成操作
虚拟机体系结构
- 一个全局类型数组(函数签名)
- 一个全局函数数组
- 一个全局变量数组
- 一个全局表格对象(元素引用)
- 一个全局内存对象
- 一个运行时栈
Hello World
JavaScript部分hello.html
1 |
|
wat部分hello.wat
1 | ;; hello.wat |
首先将.wat
编译成为.wasm
,需要用到wabt工具集。还需要下载Emscripten工具集。编译好之后配置环境变量。就可以执行了。
1 | wat2wasm hello.wat -o hello.wasm |
然后打开http://localhost:8080/xxx.html
,启动Chrome
下的开发者模式,看到执行成功。
WebAssembly核心
在JS环境中
浏览器中的wasm
运行在JS
虚拟机上,页面可以通过一组JS
对象进行wasm
模块的编译,载入,配置,调用等操作。
在wasm
中的几个关键概念都有与之对应的对象:
- 模块——
WebAssembly.Module
- 内存——
WebAssembly.Memory
- 表格——
WebAssembly.Table
- 实例——
WebAssembly.Instance