Canonical definitions for weak references and finalizers
維護者通常 4 天內回覆
還沒有人認領這個 Issue。
評估
- 難度
- 5/5
- 預估耗時
- 一週以上
- 新手友好度
- 25/100
- Issue 類型
- 功能
- 描述清晰度
- 基本清楚
- 活躍度
- 活躍
- 技術堆疊
- wasm
研究方向
Read the Component Model canonical definitions proposal in this issue and the linked discussion in issue 525, especially the comments on whether weak references and finalizers belong in the Component Model. Review the proposed validation rules, waitable behavior, and reference queue semantics. Done means the proposal’s open design questions are resolved and the canonical definitions are specified clearly enough to implement; the issue does not name code files or tests.
由索引模型根據 Issue 內容生成。
描述
As suggested in https://github.com/WebAssembly/component-model/issues/525#issuecomment-6326527037, I'm opening this issue to propose weak references and finalizers as features for the Component Model.
For context, these features would help components built in garbage collected languages (like Dart and Kotlin) reference resources from structs and arrays, registering custom callbacks to dispose them when they're no longer referenced. Even outside of the component model, weak references are commonly used on those languages to implement e.g. caches, and not having them on WASI targets prevents a full implementation of these languages.
Shouldn't this be part of core WebAssembly?
One could argue that these constructs, which are available in most popular languages using garbage collection, should be part of the core WebAssembly spec instead of the component model. However, it doesn't look like there's a current proposal to advance support for weak references or finalizers in core WebAssembly. This is also understandable, as an embedder with support for those can easily provide them as host functions without that causing a significant slowdown (that's what everyone does on the web). These custom imports should be part of the component model to share them across embedders.
Another issue is that finalizers require running callbacks, so then there's a question of when to run them (and on which thread). For example, Java uses a blocking queue that a cleaner invokes in a fresh thread, while JavaScript and Dart expect finalizers to run as event loop iterations. Encoding these expectations in WebAssembly is hard, but the component model already exposes the right primitives through waitables and its different concurrency options. So I think the Component Model is a perfect home for finalizers.
Arguably, weak references could be part of core WebAssembly. But having them in the Component Model unblocks languages from targeting it soon-ish, as opposed to the multiple years it would take to standardize this in core WebAssembly. The GC proposal includes weak references as a post-MVP proposal, but also notes that finalizers are difficult to map to WebAssembly because different languages have different expectations on how they work (something mostly solved by the component model).
From @justinfagnani in https://github.com/WebAssembly/component-model/issues/525#issuecomment-6344305004:
Shouldn't weakrefs and finalization registries be in Wasm GC proper, not the component API? This would be one more thing that a toolchain has to compile differently for core modules on JS vs components.
Weak references and finalizers are already based on function imports on the web, and changing imports to component imports doesn't affect a compiler much.
And a follow-up from @spotandjake in https://github.com/WebAssembly/component-model/issues/525#issuecomment-6346415815
I had a similar concern, if finalization registries and or weakrefs are added to the component model, it may duplicate effort or cause duplicate apis if similar wasm proposals are made as extensions to wasm gc.
I believe there are other canon builtins that will later map onto core WebAssembly features (like e.g. stack switching). So once we have them in core WebAssembly, these canon definitions could be implemented on top of those definitions.
Weak references
I propose we add two new canonical definitions:
(canon reference.create $type (core func $create))
(canon reference.get (core func $get))
validation specifies:
$createis given type(func (param (ref any)) (result (ref extern)))$getis given type(func (param (ref extern)) (result (ref null any)))- initially,
$typemust beweak. We can later support other references, like Java's soft and phantom references.
$create creates a weak reference and $get resolves it if it's still strongly reachable. A CM embedder is allowed to implement weak references with strong references, components can't assume that weak references are actually supported for their operation. For example, an embedder might choose to disable garbage collection entirely for short-lived components, and then ignore weak references.
Finalizers
Finalizers allow running callbacks asynchronously after an object has been garbage collected. I propose these canonical definitions for them:
(canon refqueue.create (core func $create))
(canon refqueue.attach (core func $attach))
(canon refqueue.detach (core func $detach))
(canon refqueue.poll (core func $poll))
(canon refqueue.drop (core func $drop))
validation specifies:
$createis given the type(func (result i32)),$dropis given the type(func (param i32)).$attachis given the type(func (param i32) (param (ref any)) (param anyref) (param anyref))$detachis given the type(func (param i32) (param (ref any)))$pollis given the type(func (param i32) (param (ref $x)) (result i32)), where$xmatches(array (mut anyref))and needs to be included as a canon option (https://github.com/WebAssembly/component-model/issues/525). Maybe we can have a non-batching poll instead to avoid having to specify a type.
refqueue.create returns an instance of a class ReferenceQueue(Waitable), meaning that reference queues can be added to waitable sets. refqueue.attach tracks a non-nullable object (the second parameter). I think tracking an i31ref should probably be a trap, but I need to figure that one out still. Once the parameter becomes unreachable, the third parameter is added to the reference queue and we call Waitable.set_pending_event to dispatch that as a notification. The fourth parameter is an optional detach token. When non-null, calling refqueue.detach can be called with that object undo an earlier attach call.
The second and fourth parameters to attach don't count towards those objects being accessible to the program. Again, this should be defined in a way that allowed embedders to never actually add anything to the reference queue. If an object is registered on multiple reference queues and becomes unreachable, it may be enqueued on any number (including none) of them. Once a held value has been enqueued, all reference.getcalls on it must return null. I don't think we need to be stricter than that (e.g. to only set weak references to null when no user code runs like in JS).
Pseudo-JS implementation of reference queues:
class ReferenceQueue extends Waitable {
#pending = [];
#registry = new FinalizationRegistry((v) => {
this.#pending.push(v);
if (this.#pending.length === 1) this.set_pending_event(/* todo: event code for refqueues */);
});
attach(object, param, detachToken) {
this.#registry.register(target, held, token ?? undefined);
}
detach(token) {
this.#registry.unregister(token);
}
poll(target) {
const popped = this.#pending.splice(0, target.length);
popped.forEach((v, i) => { target[i] = v; });
return popped.length;
}
}
I want to experiment with these builtins in jco and a Dart implementation of components, and I'll share results of that here. But feedback and discussion items on these proposals would be very welcome, thanks!
- 主要語言
- WebAssembly
- 星號
- 1.4k
- 分支
- 132
- 平均合併
- 4 天 14 小時
- 30 天內合併 PR
- 12
環境準備
這個專案沒有提供開發容器、Dockerfile 或貢獻指南,環境需要你自己搭建:先看它的 README,通用步驟見我們的新手貢獻指南。
從這裡開始
- 先讀完整個 Issue,再讀專案的貢獻指南。
- 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
- Fork 儲存庫,在一個分支上完成修改。
- 送出 Pull Request,並在描述裡引用這個 Issue 編號。
WebAssembly/component-model 的其他 Issue
-
難度 2/5 1-3 小時 新手友好度 68/100
WebAssembly/component-model#609 · 2 則留言 · 1 個 reaction ·
維護者通常 4 天內回覆
-
難度 4/5 3-5 天 新手友好度 45/100
WebAssembly/component-model#753 · 1 則留言 · 1 個 reaction ·
維護者通常 4 天內回覆
-
Does `task.return`'s memory strictly match the canon-lifted function, or only match when present?未關閉
難度 5/5 一週以上 新手友好度 18/100
WebAssembly/component-model#749 · 2 則留言 ·
維護者通常 4 天內回覆
-
難度 5/5 一週以上 新手友好度 25/100
WebAssembly/component-model#743 · 1 則留言 ·
維護者通常 4 天內回覆
-
難度 5/5 一週以上 新手友好度 25/100
WebAssembly/component-model#742 · 1 則留言 · 3 個 reaction ·
維護者通常 4 天內回覆
查看 WebAssembly/component-model 的全部 Issue
相似的 Issue
-
`Time.at(t, in: nil)` returns UTC instead of the local time (or the time zone of `t`), unlike CRuby未關閉
難度 2/5 1-3 小時 新手友好度 78/100
維護者通常 1 天內回覆
-
難度 2/5 1-3 小時 新手友好度 78/100
維護者通常 1 天內回覆
-
bug implicit-state
難度 2/5 1-3 小時 新手友好度 78/100
-
難度 2/5 1-3 小時 新手友好度 68/100
PecanProject/sipnet#435 · 1 則留言 ·
維護者通常 2 天內回覆
-
難度 2/5 1-3 小時 新手友好度 68/100