Wasmtime 中的 GC 与异常
GC and Exceptions in Wasmtime

原始链接: https://bytecodealliance.org/articles/wasmtime-gc

Wasmtime 47 已正式默认启用对 **Wasm GC** 和 **异常处理(Exceptions)** 的支持。这一里程碑成果历经多年研发,显著提升了 WebAssembly 作为高级语言编译目标的能力。 **Wasm GC** 允许具有复杂数据模型(如使用对象和数组)的语言利用 WebAssembly 运行时的原生垃圾回收器,而无需自行打包。这减少了二进制文件的体积并提高了效率。Wasmtime 通过 Cheney 风格的半空间复制回收器实现该功能,并将其封装在 Wasm 现有的线性内存架构中,以确保安全性、性能和可移植性。 **Wasm 异常处理** 用原生的 `try/catch` 结构取代了传统的、开销巨大的手动错误检查方式。由于运行时可以对非异常代码路径使用标准的展开(unwinding)机制,这不仅缩小了二进制文件体积,还加快了执行速度。 尽管目前的性能表现更侧重于正确性以及在多个短生命周期实例间的横向扩展,而非长时间运行的吞吐量,但 Wasmtime 的维护者们已经在进行编译器优化和组件模型集成的相关工作。我们鼓励用户测试这些新特性,它们扩展了可以在 Wasmtime 生态系统中高效且安全运行的语言范围。

Hacker News 最新 | 过往 | 评论 | 提问 | 展示 | 招聘 | 提交 登录 Wasmtime 中的 GC 和异常 (bytecodealliance.org) 19 分,phickey 发布于 1 小时前 | 隐藏 | 过往 | 收藏 | 讨论 | 帮助 考虑申请 YC 2026 年秋季批次!申请截止日期为 7 月 27 日。 准则 | 常见问题 | 列表 | API | 安全 | 法律 | 申请 YC | 联系 搜索:
相关文章

原文

The Wasm GC and exceptions proposals are both enabled by default in today’s Wasmtime 47 release! We are excited to help bring more languages to WebAssembly and everywhere that Wasmtime runs. Getting to this point involved large Wasmtime changes and represents the culmination of years of engineering effort.

Wasmtime

Wasmtime is a WebAssembly runtime that is fast, safe, and portable. It is standalone, lightweight, and easy to embed. Wasmtime maintainers are committed to open standards and actively participate in Wasm standardization.

Wasm GC

Originally, in the first versions of WebAssembly, high-level languages with an objects-and-references data model, as opposed to a raw-pointers-and-memory data model, had to embed their own garbage collector inside their .wasm binaries. This led to bloated .wasm binaries and many techniques often used when implementing collectors in native code, such as using stack maps and stack walking to identify GC roots, were unavailable. And, unfortunately, many languages fell into this bucket.

The Wasm GC proposal improves the situation, adding efficient support for these high-level languages to WebAssembly. It extends the WebAssembly language, allowing Wasm programs to define their own struct and array types and subtyping relationships. The Wasm program needn’t worry about managing these types’ instances’ lifetimes or manually deallocating them; the runtime handles all of that. Therefore, embedding their own garbage collector is unnecessary, and these toolchains can instead take advantage of the WebAssembly runtime’s collector. This opens the door for many more languages to easily and more efficiently target WebAssembly.

As an example, here is how a Wasm program might define a node type for a binary tree:

(rec
  (type $node (struct
    (field $key (mut f64))
    (field $left (mut (ref null $node)))
    (field $right (mut (ref null $node)))
    (field $value (mut (ref null $payload)))
  ))
)

New instances are created by struct.new $node and fields accessed via, e.g., struct.get $node $key or struct.set $node $left instructions.

Wasm Exceptions

Wasm’s exceptions proposal has goals for exception-using languages similar to the Wasm GC proposal’s goals for objects-and-references languages: it aims to enable efficient support for exceptions on WebAssembly, making WebAssembly a better compilation target for languages with exceptions. Without this proposal, toolchains would need to implement custom calling conventions that return not just function results, but also whether the function returned normally or threw an exception. Every call site must test this condition and branch appropriately, adding both bloat to the .wasm binary and runtime overhead to the common, normal-return path. However, with the exceptions proposal, all that goes away, and is replaced by throw and try/catch-style constructs. The WebAssembly runtime is then free to implement these with the classic unwinding approach that imposes zero overhead to the common, normal-return call paths, resulting in faster execution and smaller .wasm binaries.

Wasmtime’s GC Implementation

Wasmtime has a simple Cheney-style semi-space copying collector. The GC heap is divided into two halves: the “active” semi-space where new objects are allocated, and the “idle” semi-space. During collection, live objects are copied from the idle space (which was the previous active space) to the new active space, and all GC roots (e.g. active references inside Wasm stack frames) are updated to point to the new locations. Allocation is a simple bump pointer within the active semi-space and the collector does not require any read or write barriers.

We reuse WebAssembly linear memories under the covers to implement and sandbox the GC heap. A reference to a GC object is not a native pointer, it is a 32-bit index into the GC heap’s underlying linear memory. WebAssembly promises to be fast, safe, and portable, but it is the runtime that must actually shoulder that responsibility in its implementation, and reusing linear memories for the GC heap has benefits in all three dimensions. Perhaps most obvious is the defense-in-depth safety implication: even in the face of collector bugs that corrupt the GC heap, a malicious Wasm program can’t escape the sandbox to access host memory. As far as being fast goes, it lets us use virtual-memory guard pages to elide explicit bounds checks, just like we do for linear memories; we get tight integration with our pooling instance allocator, ensuring we preserve our 5-microsecond instantiation times; and, on 64-bit machines, 32-bit GC references are more compact than 64-bit pointers, more efficiently utilizing CPU caches. Finally, allocating, deallocating, and resetting large regions of memory quickly across many platforms (including bare metal!), each of which have subtly different capabilities, involves a lot of special-casing. Our existing implementation of linear memories is already portable across these platforms and already does that special-casing, so, by building our GC heap on top of a linear memory, we get a portable GC heap “for free” as well.

To further ratchet up our confidence in the collector’s correctness, we extended our fuzzing infrastructure to hammer on Wasm GC. First, we extended wasm-smith to support the GC proposal. It can, in theory, generate roughly any GC-using Wasm program, given enough time. But it might take a looong time to do that, which is why we supplemented it with two additional fuzzers:

  1. One designed to exercise interesting and arbitrary object graphs, type references, and subtyping relationships
  2. Another designed to detect heap corruption due to collector bugs or misoptimizations in our compiler

Lastly, a small note regarding performance to set expectations: we’ve mainly focused our engineering efforts on the correctness of our collector thus far, and less so on its performance. It’s brand new, and hasn’t benefited from decades of performance engineering, unlike collectors in, for example, V8 and SpiderMonkey. Our collector’s throughput and latency won’t match theirs today. Additionally, we’ve been primarily designing the collector and its trade offs for the use cases where Wasmtime is used most in production: creating many small, disposable Wasm instances, each of which is processing a small handful of tasks before it, and its GC heap, are thrown away. The system is designed first to scale horizontally across many instances rather than focusing on single-instance performance above all else. This scenario is different from, say, a single long-lived server process with indefinite lifetime; tuning a collector for it will also be different.

What’s Next

There’s always lots of performance work still to be done. We are, for example, currently in the process of extending our compiler’s alias-analysis optimizations, like store-to-load forwarding and redundant-load elimination, with GC-type information. When we know that two types can never alias, that is, they cannot occupy the same memory location, we can be more aggressive with these optimizations.

The next big milestone, functionality-wise, is to prototype GC integration with the component model on top of lazy value lowering. This effort will promote garbage-collected languages to first-class citizens in the component ecosystem, since they will no longer need otherwise-unused linear memories just to pass data across components.

Conclusion

We are excited to have reached this milestone! Give Wasmtime’s newly enabled GC and exceptions support a test run and let us know how it goes.

联系我们 contact @ memedata.com