最好的 WebAssembly 运行时可能根本不需要运行时

将 WebAssembly 模块反向编译为 C 被描述为一种无需重量级运行时即可运行受沙箱保护、可移植原生代码的方法,从而支持更安全的插件系统和跨平台二进制文件。评论者将这种方法与 Google Native Client 等早期技术进行比较,讨论 WASM 受限且规范明确的模型和工具生态为何使其适合作为通用中间层,并指出 Firefox 已经在使用这种技术。他们也强调了局限和权衡:C 内部的内存 bug 仍然存在,边界检查和确定性可能带来开销,与高级语言和 DOM 的集成仍然别扭,而一些人认为围绕 WASM 的整体热度已经超过了它在现实世界中的语言和平台支持。

Wasm→C 作为“无 VM”沙箱

  • 想法:将 C(或其他语言)编译为 WebAssembly,然后把 wasm 反向转译为 C 并原生编译,从而在不依赖重量级运行时的情况下继承 wasm 的安全保证。
  • Firefox 已经在做一种变体(RLBox):把 wasm 作为隔离边界,然后再编译回去以获得速度。
  • w2c2 目前更侧重可移植性,而不是沙箱;wasm2c 旨在实现符合规范的安全性(边界检查、类型安全的间接调用)。

安全性、边界检查与操作系统隔离

  • 有人认为这属于重复:进程本身已经通过 MMU 获得隔离;经典的 seccomp 风格沙箱和容器在安全性上可以不低甚至更高,而且 syscall 面更窄。
  • 也有人说,内嵌 wasm 在无法启动进程/容器的场景下很有吸引力,尤其适合插件式用途。
  • Wasm 依赖强制边界的线性内存;生产级引擎使用 guard pages 加上 mprotect/故障处理程序,实现几乎零成本的检查。
  • 一个重要限制:wasm 不能修复逻辑 bug 或模块内部的内存破坏;不受信任的模块与宿主隔离了,但模块内部不安全的 C 仍然是不安全的。

NaCl、PNaCl,以及 wasm 是怎么来的

  • Native Client 解决了类似问题,但只适用于特定 CPU;PNaCl 的 LLVM bitcode 传输格式以及与 glibc 的纠缠都很混乱。
  • asm.js 作为更简单的替代方案出现;wasm 则是对这些经验的多方标准化。
  • 有人认为 NaCl 的失败主要是技术原因;也有人更强调政治 / 生态原因。

C vs LLVM IR vs 其他 IR

  • 支持 C:C 稳定、支持广泛,并且可作为可移植 IR 使用,甚至包括一些冷门操作系统(例如 Mac OS 9、奇特 CPU)。
  • 反对 C:C 无法表达更丰富的别名信息、和类型和详细的 UB 处理;LLVM IR 会更有表现力,但它是不断变化的目标,而且版本强绑定。
  • 观点:把 wasm 看作通用中间层(<任何语言>→wasm→C/任何东西),而不是在每个 C 编译器里硬塞边界检查。

字节码设计与性能争论

  • 有人批评 wasm 采用基于栈的设计,相比基于寄存器的 IR 增加了复杂性;也有人认为这已足够且经过实战验证。
  • 对 wasm 随着增长会在多大程度上保持“通用”存在分歧(GC、线程、更丰富的特性),还是会像 JVM/CLR 一样变得带有明确立场。

用例、炒作与怀疑论

  • 支持者:wasm 是一种用于沙箱化插件、无服务器、嵌入式、跨语言库和软件保存的可移植 ISA;网络效应胜过技术瑕疵。
  • 怀疑者:炒作夸大了新颖性和安全性;现有字节码和 VM 几十年来一直在解决类似目标;wasm 并不会从根本上解决 Web UI 的痛点(HTML/CSS/JS 的复杂性)。
  • 有人认为,浏览器之外的 wasm(WASI、插件系统、Cosmopolitan 风格打包)比浏览器应用更有影响力。

GC、高级语言与 DOM

  • 预期 Wasm GC 会帮助托管语言,但也有人担心它与 Go/Java 之类运行时不匹配,并且缺少高效的栈切换等能力。
  • Wasm 不能直接操作 DOM/WebGPU;需要 JS 适配层。有些人想要完全不依赖 JS 的 Web 应用;也有人认为 DOM/Web API 本来就更适合 JS 形态,而且相对于 DOM 成本,这点开销可以忽略不计。