Web Assembly基础
前言
WebAssembly
也称为 wasm
,它是对 Javascript
的改进。
它旨在像 javascript
一样在浏览器中运行,也可以 在nodejs
环境中运行。
当任何高级语言如 C
、C++
、Rust
被编译时,你可以得到 wasm
输出。
工具
示例
int factorial(int n) {
if (n == 0)
return 1;
else
return n * factorial(n-1);
}
将上述代码放入左侧源码输入框然后编译,效果如下所示:
wat
文本内容 转为 wasm
的方式,将文本格式内容贴到输入框内,立即可以看到 wasm
汇编代码
栈模型机
在 WASM
中,所有指令都被推入堆栈。参数被弹出,结果被推回堆栈。 查看关于两个数的加法 WebAssembly
程序−
(module
(func $add (param $a i32) (param $b i32) (result i32)
get_local $a
get_local $b
i32.add
)
(export "add" (func $add))
)
该函数的名称为 $add
,它接收2个参数$a
和$b
。结果是 32 位整数类型。使用get_local
访问本地变量,使用 i32.add
执行添加操作。 执行时添加 2 个数字的堆栈表示将如下−
- 步骤:
步骤 | 描述 |
---|---|
1 | 执行 get_local $a 指令,即第一个参数,即 $a 入栈。 |
2 | 在执行 get_local $b 指令时,第二个参数(即$b 入栈 入栈)。 |
3 | i32.add 的执行将弹出堆栈中的元素,并将结果推回堆栈。堆栈内最终保留的值是函数$add 的结果。 |
安装依赖
在这一章中,将学习如何安装 Emscripten SDK
来编译C/C++
。Emscripten
是一款低级别虚拟机器 (LLVM
),它采用 C/C++
生成的字节代码,并将其编译到 JavaScript
中,以便于在浏览器内执行。
- 安装 sdk
克隆项目源码:
git clone https://github.com/emscripten-core/emsdk.git
下一步 进入emsdk
目录并获取最新代码并安装最新版本的 sdk
cd emsdk
## windows
emsdk install latest
## linux 这个命令将需要一些时间来安装必要的工具,如Java,Python等。请按照以下代码−
./emsdk install latest
- 激活环境
## windows
emsdk_env.bat
## linux
source ./emsdk_env.sh
编译
我们已经完成了安装 emsdk
,现在可以编译 C
或C++
代码
emcc source.c or source.cpp -s WASM=1 -o source.html
输出将为您提供一个source.html
文件、source.js
和source.wasm
文件。js
api
,将获source.wasm
,当你点击source.html
在浏览器中。你可以看到输出
仅获取 wasm
文件。此命令将只为您提供source.wasm
。
emcc source.c or source.cpp -s STANDALONE_WASM
在线编译工具
首先,您可以单击 Empty C Project
, Empty Rust Project
, Empty Wat Project
将他们编译为 wasm
它有生成,运行来构建代码并检查输出。下载按钮允许您下载。wasm
文件,可用于在浏览器内测试。此工具非常有助于编译 C
和 Rust
代码并检查输出
WASM 程序结构
- 示例代码
(module
(type $t0 (func))
(type $t1 (func (result i32)))
(func $__wasm_call_ctors (type $t0))
(func $main (export "main") (type $t1) (result i32)
i32.const 42)
(table $T0 1 1 anyfunc)
(memory $memory (export "memory") 2)
(global $g0 (mut i32) (i32.const 66560))
(global $__heap_base (export "__heap_base") i32 (i32.const 66560))
(global $__data_end (export "__data_end") i32 (i32.const 1024)))
WebAssembly
,也称为 WASM
,是开发的二进制格式低级别代码,以最有效的方式在浏览器内执行
概念
- 值
- 类型
- 指令
值
WebAssembly
中的值用于存储复杂数据,例如文本、字符串和向量。
WebAssembly
支持以下内容 -
- Bytes 字节
- Integers 整型
- Floating point 浮点型
- Names 名称
Bytes
字节是 WebAssembly
C 支持的最简单的值形式。其价值是16进制格式。 例如,以b
为代表的字节也可以取自然数字n
,其中n<256
。
整数
在 WebAssembly
中,支持整数如下
- i32:32 位整数
- i64: 64 位整数
浮点
WebAssembly
中支持的浮点数字如下
- f32: 32 位浮点数
- f64: 64 位浮点数
名称
名称是字符序列,由 Unicode
定义的标量值,可在此处给出的链接 unicode提供。
Types
WebAssembly
中的实体被归类为类型。所支持的类型如下所述−
- Value Types
- Result Types
- Function Types
- Limits
- Memory Types
- Table Types
- Global Types
- External Types
值类型
支持的值类型如下所述
- i32:32 位整数
- i64: 64 位整数
- f32: 32 位浮点型
- f64: 64 位浮点型
结果类型
括号内的值执行并存储在结果类型中。结果类型是由值组成的代码块执行的输出。
函数类型
函数类型将接收参数的向量,返回向量的结果。
functype::=[vec(valtype)]--> [vec(valtype)]
限制类型
限制是与内存和表类型相关的存储范围。
limits ::= {min u32, max u32}
内存类型
内存类型处理线性内存大小范围。
memtype ::= limits
表类型
表类型按分配给它的元素类型进行分类。
tabletype ::= limits elemtype
elemtype ::= funcref
表类型取决于分配给它的最小和最大尺寸的限制。
全局类型
全局类型 持有具体值、可以更改或保持不变的全局变量。、
globaltype ::= mut valtype
mut ::= const|var
外部类型
外部类型涉及导入和外部值。
externtype ::= func functype | table tabletype | mem memtype | global globaltype
指令
WebAssembly
遵循堆栈机模型的一系列指令。当 遵循时,指令入堆栈。 例如,函数的参数值从堆栈中弹出,结果入堆栈上。最终,堆栈中只有一个值,这就是结果。
一些常用的指令如下−
- 数字指令
- 变量指令
数字指令
数字指令是按数字值执行的操作。
eg:
nn, mm ::= 32|64
ibinop ::= add|sub|mul|div_sx|rem_sx|and|or|xor
irelop ::= eq | ne | lt_sx | gt_sx | le_sx | ge_sx
frelop ::= eq | ne | lt | gt | le | ge
变量指令
变量指令是关于获取本地和全局变量。
eg:
- 访问本地变量
get_local $a
get_local $b
- 设置本地变量
set_local $a
set_local $b
- 获取全局变量
get_global $a
get_global $b
- 设置全局变量
set_global $a
set_global $b
JS
WASM
之所以出现,并不是要取代 javascript
,而是要处理某些难以用 javascript
处理的事情。
eg:
图像识别、CAD
应用程序、实时视频增强、VR
和增强现实、音乐应用程序、科学可视化和模拟、游戏、图像/视频编辑等任务很难用 javascript
来完成。
使用现在可以编译为 WebAssembly
的 C/C++
、Rust
等高级语言,很容易完成上述任务。
WebAssembly 生成易于在浏览器中执行的二进制代码。
所以这里是 Javascript
和 WebAssembly
之间的比较列表。
参数 | Javascript | WebAssembly |
---|---|---|
代码 | 您可以轻松地在 Javascript 本中编写代码。编写的代码是可读的,并保存为 .js 。在浏览器中使用时,您需要使用<script> 标。 | 该代码可以以 WebAssembly 形式以文本格式编写,并保存为.wat 。很难以.wat 格式编写代码。最好从其他高级语言中编译代码,而不是从.wat 开始编写。 您无法在浏览器内执行.wat 文件,并且必须使用可用的编译器或在线工具转换为.wasm 。 |
执行 | 在浏览器中使用时,必须下载、解析、编译和优化用 javascript 编写的代码。 | 已经编译成二进制格式 |
内存管理 | Javascript 在创建变量时分配内存,在未使用时释放内存并添加到垃圾收集中。 | WebAssembly 的内存是一个存储数据的阵列。您可以使用 Javascript API WebAssembly.memory(). 来分配内存。WebAssembly 以阵列格式存储,即易于理解和执行执行的平面内存模型。 WebAssembly 中内存模型的缺点是 <table><tr> <th>缺点</th></tr><tbody><tr><td>耗时复杂计算</td></tr><tr><td>不支持垃圾回收,不允许重复使用内存,造成内存浪费</td></tr></tbody></table> |
加载事件、性能 | 在 javascript 的情况下,当在浏览器内调用时,必须下载并解析 javascript 文件。稍后,解析器将源代码转换为字节代码,即 javascript 引擎在浏览器中执行代码。 Javascript 引擎非常强大,因此,与 WebAssembly 相比,javascript 的加载时间和性能非常快。 | 最重要的目标是比 JavaScript 更快。 高级语言生成的 Wasm 代码尺寸较小,因此加载时间更快。 但是,像 GO 这样的语言,当编译到 wasm 时,会为一小块代码生成一个大文件大小。 WebAssembly 设计速度更快,可跨所有主要浏览器运行。与 javascript 相比,WebAssembly 仍需要在性能方面增加许多改进。 |
调试 | Javascript 是可读的,易于调试。在浏览器中添加 javascript 代码的断点可轻松调试代码。 | WebAssembly 以文本格式提供代码,这是可读的,但是,仍然很难调试。Firefox 允许您在浏览器内以.wat 格式查看大体代码。 您无法在.wat 中添加断点,这或许在将来可用的 |
浏览器支持 | Javascript 在所有浏览器中都工作得很好 | 所有主要的 Web 浏览器都支持 。 |