WebAssembly和Wabt

Abstract

最近参加deeplang的的过程中,接触到了一些编译领域的新技术,总结一下希望有时间了可以进一步的深入了解。参考资料是WebAssembly标准入门

Points

过去很多技术尝试将C/C++程序直接运行在浏览器中,比如TypeScriptC/C++代码转换为JS

  • Emscripten

而这个项目利用LLVM编译器前端编译C/C++代码,生成LLVM平台特有的跨平台中间语言代码,最终再将IR转换为JavaScriptasm.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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Show me the answer</title>
</head>
<body>
<script>
var wasmMem = new WebAssembly.Memory({initial:1});
function printStr(offset, length){
var bytes = new Uint8Array(wasmMem.buffer, offset, length);
var string = new TextDecoder('utf-8').decode(bytes);
console.log(string);
};
var importObj = {js : {print: printStr, mem: wasmMem}};
fetch('hello.wasm').then(response=>
response.arrayBuffer()
).then(bytes=>
WebAssembly.instantiate(bytes, importObj)
).then(result => result.instance.exports.hello()
);
</script>
</body>
</html>

wat部分hello.wat

1
2
3
4
5
6
7
8
9
10
11
12
13
 ;; hello.wat

(module
;; import js::print as js_print();
(import "js" "print" (func $js_print (param i32 i32)))
(import "js" "mem" (memory 1)) ;;import js::mem as memory
(data (i32.const 0) "你好,wasm")
(func (export "hello")
i32.const 0 ;; pass offset 0 to js_print
i32.const 13 ;; pass offset 13 to js_print
call $js_print
)
)

首先将.wat编译成为.wasm,需要用到wabt工具集。还需要下载Emscripten工具集。编译好之后配置环境变量。就可以执行了。

1
2
$ wat2wasm hello.wat -o hello.wasm
$ emrun --no_browser --port 8080 .

然后打开http://localhost:8080/xxx.html,启动Chrome下的开发者模式,看到执行成功。

WebAssembly核心

在JS环境中

浏览器中的wasm运行在JS虚拟机上,页面可以通过一组JS对象进行wasm模块的编译,载入,配置,调用等操作。

wasm中的几个关键概念都有与之对应的对象:

  • 模块——WebAssembly.Module
  • 内存——WebAssembly.Memory
  • 表格——WebAssembly.Table
  • 实例——WebAssembly.Instance

WebAssembly汇编语言

本文标题:WebAssembly和Wabt

文章作者:HaotianMichael

发布时间:2020年11月12日 - 09:11

最后更新:2022年03月16日 - 17:03

原始链接:http://haotianmcihael.github.io/2020/11/12/WebAssembly和Wabt/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。