Canonical definitions for weak references and finalizers
Los mantenedores suelen responder en 4 días
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 5/5
- Tiempo estimado
- Más de una semana
- Aptitud para principiantes
- 25/100
- Tipo de issue
- Nueva funcionalidad
- Claridad
- Bastante claro
- Estado de actividad
- Activo
- Stack tecnológico
- wasm
- Área
- backend-api-design
Línea de trabajo
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.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
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!
- Lenguaje dominante
- WebAssembly
- Estrellas
- 1.4k
- Forks
- 132
- Merge medio
- 4 d 14 h
- PR fusionados (30 d)
- 12
Preparar el entorno
Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de WebAssembly/component-model
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
WebAssembly/component-model#609 · 2 comentarios · 1 reacción ·
Los mantenedores suelen responder en 4 días
-
Dificultad 4/5 3-5 días Aptitud para principiantes 45/100
WebAssembly/component-model#753 · 1 comentario · 1 reacción ·
Los mantenedores suelen responder en 4 días
-
Does `task.return`'s memory strictly match the canon-lifted function, or only match when present?Abierto
Dificultad 5/5 Más de una semana Aptitud para principiantes 18/100
WebAssembly/component-model#749 · 2 comentarios ·
Los mantenedores suelen responder en 4 días
-
Dificultad 5/5 Más de una semana Aptitud para principiantes 25/100
WebAssembly/component-model#743 · 1 comentario ·
Los mantenedores suelen responder en 4 días
-
Dificultad 5/5 Más de una semana Aptitud para principiantes 25/100
WebAssembly/component-model#742 · 1 comentario · 3 reacciones ·
Los mantenedores suelen responder en 4 días
Todos los issues de WebAssembly/component-model
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
Huber-group-EMBL/Rarr#294 ·
Los mantenedores suelen responder en 1 día
-
needs attention untriaged
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet#3666 ·
Los mantenedores suelen responder en 3 días
-
agent-butler-finding bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
jordansmall/spindrift#6414 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
palladius/rails8-app-on-gcp#198 ·
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 77/100
Hochfrequenz/sapgui.mcp#1039 ·
Los mantenedores suelen responder en 1 día