WebAssembly 运行时 可视化实验室
用交互式 SVG 呈现 WASM 指令集、编译流程、内存模型、WASI 接口、JIT 编译等 WebAssembly 核心技术。八个模块,纯原生实现,可直接在浏览器中探索 WASM 运行时的核心结构。
WASM 指令集:栈式虚拟机
WebAssembly 采用栈式虚拟机,指令操作隐式栈顶。i32/i64/f32/f64 四种值类型。逐步执行一段加法与乘法程序,观察操作数 push/pop 与执行过程。
栈式执行模型
点击“单步”逐步执行 WASM 字节码。每条指令从栈顶弹出操作数、计算后压回结果。栈式设计让编码紧凑(无寄存器字段),但需要更多指令完成同一运算。
编译到 WASM
C/C++/Rust 源码经 LLVM 前端生成 LLVM IR,再由 LLVM WASM 后端或 Wasm-ld 产出 .wasm 字节码。逐步观察从源码到字节码的编译流水线。
编译阶段
点击“单步”推进编译流水线。Clang/rustc 把源码解析为 AST 并生成 LLVM IR(SSA 形式);LLVM 经过优化 pass 后由 WASM 后端 lowering 为字节码;wasm-ld 链接多个模块并产出最终 .wasm。
内存模型:线性内存
WASM 使用一段连续可增长的 Linear Memory(默认 1 页=64KB)。栈向下生长、堆向上分配,i32/i64 load/store 通过基址+偏移访问。触发 memory.grow 观察扩容。
线性内存说明
Linear Memory 是一段 ArrayBuffer,最大 4GB(i32 索引)。WASM 模块不直接管理堆,由嵌入语言或 WASI libc malloc 分配。memory.grow 申请追加整数页,返回旧大小(页数)。
WASI 接口
WebAssembly System Interface 为 WASM 提供能力化(capability)系统调用抽象。fd/path/sock 三类接口通过预开放句柄访问,杜绝全局文件系统。切换接口观察调用链。
WASI 接口说明
WASI 采用 capability-based 安全模型:模块只能通过显式传入的 preopened fd 访问文件,无全局 root。fd_read/fd_write 处理 I/O;path_open 在已授权目录下打开;sock_accept 处理网络。
模块加载与链接
WASM 模块生命周期:fetch 字节码 → WebAssembly.compile 编译为 Module → instantiate 实例化(绑定 import)→ 获得 export 调用。逐步观察 import/export 表链接。
加载阶段
compile 阶段做验证与编译(同步或 WebAssembly.compileStreaming 流式);instantiate 阶段把 import 表(函数/内存/表/全局)绑定到宿主提供的对象,再执行 start 函数初始化;导出的函数可被 JS 调用。
JIT 编译:分层 tier-up
浏览器 WASM 引擎采用分层编译:解释器 / 基线编译器(Liftoff/Tier-1)快速产出机器码;热点函数由优化编译器(TurboFan/Maglev/Tier-2)重编译。触发热点观察 tier-up。
分层编译策略
函数首次调用走解释器;调用计数达阈值后 Liftoff 快速生成未优化机器码(启动快);累计更多调用后 TurboFan 基于类型反馈重编译,内联与寄存器分配使性能接近原生。
安全沙箱模型
WASM 默认运行在零信任沙箱:默认无 I/O、无网络、无文件系统。能力(capability)必须显式授予;同源策略与 CSP 限制模块来源;线性内存隔离。切换能力观察边界。
安全机制
WASM 模块只能调用宿主显式提供的 import 函数——默认无任何系统访问。线性内存与执行栈独立、控制流验证保证安全;CSP 限制可加载的 .wasm 来源;COOP/COEP 启用后可使用 SharedArrayBuffer 多线程。
性能对比:JS vs WASM vs Native
不同运行时在不同负载下表现差异:JS 依赖 JIT 与 GC;WASM 接近原生但跨边界有开销;Native 直接受益于 SIMD 与缓存。切换基准测试观察相对性能。
基准测试
数值密集负载下 WASM 比 JS 快 1.5-3 倍(无 GC、可预测类型);与 Native 差距约 10-30%(边界开销、缺少自动 SIMD)。DOM/字符串操作 JS 更优(已有优化)。AOT 编译消除启动 JIT 开销。