原文链接

这是 WebAssembly 系列的第四篇,如果你没读过第一篇,我建议你读下。

WebAssembly 是除了 JavaScript 外另一种在网页上面运行的编程语言。在过去,假如想要在浏览器上面运行,与网页的各部分交互,唯一的选择是 JavaScript。

因此当人们谈到 WebAssembly 执行的快,是相对于 JavaScript 而言的。但并不意味着你必须在 WebAssembly 与 JavaScript 选其中一个。

事实上,我们期望开发者在同一个应用中,同时使用 WebAssembly 和 JavaScript。即使你不自己编写 WebAssembly,你也能从中受益。

WebAssembly 模块定义的函数可以在 JavaScript 中被调用。就像你从 npm 上面下载了 lodash 的模块,然后通过调用它的 API 调用它导出的函数,在未来你可以下载 WebAssembly 的模块。

让我们看下如何创建一个 WebAssembly 模块,然后如何在 JavaScript 中调用它。

WebAssembly 适合哪里?

在讲汇编速成课这一章,我讲了编译器是如何将高级语言转换为机器语言的。

WebAssembly 可以融入到图中的哪一部分?

你可能会认为它是另一个目标汇编语言,这是对的,除了 x86 和 ARM 都对应于特定的机器架构。

当将你的代码在用户的机器上面通过 web 传送去执行的时候,你不知道你的代码会在哪个机器架构上面运行。

因此 WebAssembly 和其他汇编语言有点儿不同。它是一个概念机器的机器语言,并不是真实的物理机。

因此,WebAssembly 的指令有时候也被称为虚拟指令。它们相对于 JavaScript 源代码对于机器语言有一个更直接的映射。它们代表了普遍流行的硬件上面可以高效完成的一种交叉。但它们并不直接映射特定硬件的特定机器语言。

浏览器下载 WebAssembly。然后把 WebAssembly 编译为特定机器的汇编。

编译为 .wasm

被称为 LLVM 的编译工具链目前提供了对 WebAssembly 的大部分支持。

假设从 C 编译到 WebAssembly。用前端(此前端非彼前端) clang 将 C 转换为 LLVM 的中间表示形式。LLVM 可以理解这种中间表示,然后对此做一些优化。

从 LLVM 的中间表示到 WebAssembly ,我们需要后端(此后端也非彼后端,这里的前端后端指的是从 LLVM 编译工具链的不同阶段)支持。在 LLVM 项目中也有一个在开发中的后端。大多数工作在后端,很快就能完成,不过目前还没有实现。

有另一个被称为 Emscription 的工具,目前相对来说是比较容易使用的。它有自己的后端,可以通过编译到另外一个目标(asm.js)生成 WebAssembly,然后将 asm.js 再转换为 Web Assembly。它底层使用的 LLVM,你可以在 Emscripten 中在两个后端之间切换。

Emscripten 包含额外的工具和库允许移植整个 C/C++ 代码库,比编译器的软件开发包(SDK)更多。例如,系统开发人员习惯于拥有一个可以读写的文件系统,因此 Emscripten 可以使用 indexedDB 模拟一个文件系统。

无论你使用的什么工具链,最后的结果都是一个以 .wasm 为后缀的文件。下面我将介绍更多的 .wasm 文件结构。首先,让我们看下如何在 js 中使用它。

在 JavaScript 中加载一个 .wasm 模块

.wasm 文件是 WebAssembly 模块,可以在 JavaScript 中加载。加载的过程有点儿复杂。

function fetchAndInstantiate(url, importObject) {return fetch(url).then(response =>response.arrayBuffer()).then(bytes =>WebAssembly.instantiate(bytes, importObject)).then(results =>results.instance);
}

想要深入了解点击此链接

我们正在努力让这个过程变得更加简单。我们希望改进工具链,并且与现有的打包工具如 webpack 或者 加载器 SystemJs 集成。我们相信加载 WebAssembly 模块和加载 javascript 文件那样简单。

WebAssembly 模块和 JS 模块之间有一个主要的区别,当前,WebAssembly 中的函数只能使用数值类型参数(整数或者浮点型)或者 数值类型返回值。

对于其他一些数据类型比较复杂,比如字符串,不得不使用 WebAssembly 模块的内存。

如果你使用 JavaScript 比较多,可能对直接访问内存不太熟悉。性能更高的语言,比如 C,C++,Rust,倾向于手动管理内存。WebAssembly 模块内存模拟在其他语言中的堆。

为了做到这些,使用了 javascript 中的 ArrayBuffer。buffer 数组是字节码的数组。所以数组的索引作为内存地址。如果你想在 JavaScript 和 WebAssembly 之间传递字符串,你将字符转为等价的字符码。然后将它写入内存数组里。因为索引是整型的,所以索引可以传入到 WebAssembly 函数中。因此字符串的第一个字符所以可以作为指针。

好像任何一个开发被 web 开发人员使用的 WebAssembly 模块的开发人员要创建一个模块包裹器(wrapper) ,你作为一个模块使用者不需要知道内存管理。

如果你想要学的更多,看下关于使用 WebAssembly 内存文档。

.wasm 文件的结构

如果你编写高级语言的代码,然后编译为 WebAssembly,你不需要知道 WebAssembly 模块结构是什么。但有助于理解基础。

如果你还没有准备好,我们建议读一读关于汇编那一篇(系列第三篇)。

这里有一个 C 函数,我们将会把它编译为 WebAssembly:

int add42(int num) {return num + 42;
}

你可以使用 WASM Explorer 编译函数。

如果你打开 .wasm 文件(如果你的编辑器支持),你将会看到想到像这样。

00 61 73 6D 0D 00 00 00 01 86 80 80 80 00 01 60
01 7F 01 7F 03 82 80 80 80 00 01 00 04 84 80 80
80 00 01 70 00 00 05 83 80 80 80 00 01 00 01 06
81 80 80 80 00 00 07 96 80 80 80 00 02 06 6D 65
6D 6F 72 79 02 00 09 5F 5A 35 61 64 64 34 32 69
00 00 0A 8D 80 80 80 00 01 87 80 80 80 00 00 20
00 41 2A 6A 0B

这是一个 “二进制” 表示的模块。在二进制上面有双引号,因为通常以十六进制表示的,但是很容易转换为二进制的,或者人类可读的格式。

例如,下面是 num + 42 .

代码是如何工作的:堆栈机

如果你想知道,下面是那些指令做的。

你可能注意到 add 这个操作并没有表明值来自哪里。这是因为 WebAssembly 是一个堆栈机的例子。意味在操作执行之前,所需要的值需要在栈上排列。

像 add 操作知道它们需要多少值。add 需要两个,它需要从栈顶获取两个值。这意味着 add 指令可以更少(一个字节),因为指令不需要指定源或者目的寄存器。这减少 .wasm 文件的大小,意味着花费更少的下载时间。

尽管 WebAssembly 定义涉及到堆栈机,并不是讲如何在物理机上工作的。当浏览器将 WebAssembly 转换为浏览器运行的机器的机器码,它使用寄存器。尽管 WebAssembly 代码没有指定 寄存器,它给了浏览器使用最多机器寄存器回收更多的灵活性。

模块的部分(sections)

除了 add42 函数本身,.wasm 文件中还有其他的。这些被称为部分(sections)。它们中的一些是任何一个模块必须的,另一些是可选的。

必须的:

  1. Type. 包含这个模块中定义的函数的函数签名
  2. Function. 模块中每个函数的索引
  3. Code. 这个模块中每个函数真实的函数体。

可选的:

  1. Export. 将函数,内存,表 和 全局变量导出到其他的 WebAssembly 模块和 JavaScript。这允许分别编译的模块动态链接到一起。This is WebAssembly’s version of a .dll.
  2. Import. 指定函数,内存,表和从另一个 WebAssembly 模块或者 JavaScript 导入的全局变量。
  3. Start. 一个在 WebAssembly 模块加载完自动执行的函数(有点儿像主函数)。
  4. Global. 为模块声明全局变量
  5. Memory. 定义模块将会用到的内存
  6. Table. 将值映射到外部 WebAssembly 的模块成为可能,例如,javascript 对象。这对于间接函数调用尤其有用。
  7. Data. 初始化导入或者本地内存。
  8. Element. 初始化导入和本地表

关于 sections 更多的知识,可以进入 sections 是如何工作的 深入了解。

接下来

现在你知道如何处理 WebAssembly 模块了,让我们知道为什么 WebAssembly 执行这么快。

译者注:一个可以在线体验 webAssembly 网站

如何为prel语言加载模块_WebAssembly 系列(第四部分)- 创建和使用WebAssembly模块...相关推荐

  1. python调用r语言加载包错误_Python调用R语言

    网络上经常看到有人问数据分析是学习Python好还是R语言好,还有一些争论Python好还是R好的文章.每次看到这样的文章我都会想到李舰和肖凯的<数据科学中的R语言>,书中一直强调,工具不 ...

  2. C#使用SQLite出错:无法加载 DLL“SQLite.Interop.dll”,找不到指定的模块

    在.net中使用sqlite数据库需要引用SQLite.Interop.dll引用,一帮添加两文件夹就可以了 64的和32位的里面分别包含了SQLite.Interop.dll 测试里也加上 但是有时 ...

  3. QT多国语言加载qm文件不起效果问题总结

    请确保qm的文件路径正确,该文件程序一定能找得到. 当有多个qm文件时,后加载的可能会覆盖掉前期加载的,请检查是不是后加载的qm导致多国语言失败. 请检查QTranslator对象在窗口.程序生存期内 ...

  4. 【Android 安全】DEX 加密 ( 代理 Application 开发 | 加载 dex 文件 | 使用反射获取方法创建本应用的 dexElements | 各版本创建 dex 数组源码对比 )

    文章目录 一.不同 Android 系统创建 dex 数组源码对比 二.不同 Android 系统创建 dex 数组源码对比 三. Android 5.1 及以下系统反射方法并创建 Element[] ...

  5. Spark _25.plus _使用idea读取Hive中的数据加载成DataFrame/DataSet(四)

    对Spark _25 _读取Hive中的数据加载成DataFrame/DataSet(四) https://georgedage.blog.csdn.net/article/details/10309 ...

  6. 【学习分享】2、创龙 TMS320C6748开发板程序加载和烧写(四)

    此部分由于篇幅过长,将分为五个小点进行叙述,此处主讲基于SD卡烧写程序到NAND FLASH,所用器件为创龙TMS320C6748开发板.需要注意的点已在备注中进行说明. 如果需要从头开始进行本使用手 ...

  7. 解决 go 语言加载模块超时 https://proxy.golang.org i/o timeout

    Go 语言下载 module 超时 go 语言下载模块的默认地址是 https://proxy.golang.org,而该网址在国内无法正常访问,若以该网址作为源加载模块则会出现下面的问题: PS E ...

  8. 模块加载及第三方包:Node.js模块化开发、系统模块、第三方模块、package.json文件、Node.js中模块的加载机制、开发环境与生产环境、cookie与session

    1.Node.js模块化开发 1.1 JavaScript开发弊端 JavaScript 在使用时存在两大问题,文件依赖和命名冲突. 1.2 软件中的模块化开发 一个功能就是一个模块,多个模块可以组成 ...

  9. python调用r语言加载包错误_Python中调用R语言包指南.docx

    Python中调用R语言包指南R语言是非常强大的做统计分析和建模方面的开源软件,它有非常丰富的统计软件包,做统计可以说只有你想不到的,没有R办不到的.Python又是当下最流行的编程软件之一,Pyth ...

最新文章

  1. 三菱je-a系列伺服支持modbusrtu 协议吗_入门课程 | 三菱FX系列PLC的软元件介绍
  2. rabbitmq 限制速度_=(:) RabbitMQ详解
  3. 李飞飞最新论文:用算法判断政治倾向(附论文链接)
  4. 东莞厚街工业机器人展会_工业机器人四大家族齐聚!东莞将在12月举办智博会...
  5. 我怀疑对象做了什么对不起我的事......
  6. [html] html5都有哪些新的特性?移除了哪些元素?
  7. crawler_java_数据平台结构
  8. 1000个摄像头的网络怎么搭建?为什么500个就卡的不行?
  9. mysql-cluster 安装篇(1)---简介
  10. cisco4503端口镜像配置
  11. 从Slice_Header学习H.264(三.2)--相关细节之 参考图像列表
  12. 如何打造自动驾驶的数据闭环
  13. c++ overload
  14. Gitee创建仓库拉人
  15. 领英精灵和领英助理哪个好,看这一篇就够了
  16. Beta分布(Beta Distribution)
  17. 【BYM】Android 仿百度搜索列表滑动效果,flutter环境搭建
  18. html 图片自动滚动播放,javascript+html5实现仿flash滚动播放图片的方法
  19. PAT:A1015. 德才论 (0/25)
  20. BBM(Bad Block Management)坏块管理

热门文章

  1. 实战演练丨SCN太大引发ORA-600[2252]
  2. 关于深度学习编译器,这些知识你需要了解一下
  3. 搞定研发知识管理,你的企业就能跑快一步
  4. 物联网打工人必备:LiteOS Studio图形化调测能力
  5. 十八般武艺玩转GaussDB(DWS)性能调优(三):好味道表定义
  6. 想被千年后的人知道吗,快去GitHub上传代码吧!
  7. HBase(2) Java 操作 HBase 教程
  8. javascript基础修炼——手把手教你造一个简易的require.js
  9. oracle存储tar,Linux环境使用TAR命令快速部署安装Oracle
  10. cr全称是什么意思_轻生未遂?她到底经历了些什么......