You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Apr 25, 2025. It is now read-only.
Repository navigation
This repository was archived by the owner on Apr 25, 2025. It is now read-only.
Another post-MVP feature to consider would be a way to compare funcrefs for equality and/or get unique IDs for them or something.
Then I could do speculative inlining of funcrefs as a Wasm-to-Wasm pass in Winliner instead of only for call_indirects through tables that are never mutated.
Implementation perspective: if we expect that repeated creations of funcrefs for the same function index have distinct identity (in other words, that (ref.eq (ref.func $x) (ref.func $x)) evaluates to 0), then that would be annoying/inefficient to implement. If we specify that funcrefs are implicitly cached/canonicalized, i.e. there is only one unique funcref returned by arbitrarily many executions of (ref.func $x) for a given $x, then that would be trivial to implement -- in fact, we already make use of this property (and pointer-equality comparisons based on it) internally in V8.
(To be fair, I cannot say with certainty whether other engines might see this differently, but I would find that somewhat surprising: the obvious way how to make ref.func fast is to cache or even pre-initialize its result, so it doesn't need an allocation every time.)
One of the known problems with function identity is that it invalidates optimisations like specialisation or any code transformation duplicating/merging function definitions that are referenced.
Previous discussion on function comparisons: #239 , some use cases and data there from a year ago.
Overall I think this can help in the toolchain, as @fitzgen said, but I also agree with @rossberg that the downsides need to be carefully weighed here. Another thing to consider is that if VMs inline at runtime then this probably becomes less important, and for that reason I don't consider this high priority personally.
Still, for Hoot, I would like to be able to distinguish between different funcrefs; besides specialization, it would be useful for debugging and introspection. All I really need though is to be able to get an i32 associated with the funcref's code.
Perhaps there would be a way to keep funcrefs as non-comparable by default, but allow a module to declare some set of functions as having visible addresses, possibly via designating an element section, where addresses are assigned sequentially starting from 0. Then you could have func.get_addr retrieve the address for a funcref. If the funcref is not from the current instance (module?) it would return -1 or something. Could this be sufficient for the devirtualization use case?
In Hoot probably we have to build something terrible, like putting all funcrefs in a host-side hash table or something. A Wasm facility would be quite welcome.
Edit: Turns out, I need to distinguish between instances; given an open-world system with instances A and B, sequential allocation from 0 within a module doesn't do it. Still working on a solution; I can wrap everything in a struct but that is quite some overhead for a basic ability which is present under the hood (equality and hashing).
for a basic ability which is present under the hood (equality and hashing).
Well, the reason for not exposing this is that it in fact may not be present under the hood, e.g., due to optimisations etc.
But yeah, this feature is already listed in the Post-MVP doc.
My preferred mechanism would be something a bit more generic, where we allow type definitions to specify whether references to them support equality or not. For functions, this would allow knowing at definition site whether a function may need to be handled carefully to preserve equality. For structs, defining them as non-eq would essentially give us value types. (I thought this was somewhere in the Post-MVP doc, but apparently I never included it there.)
Activity
rossberg commentedon Oct 17, 2023
You meant October 12? :)
Many of those are already listed in the Post-MVP doc in some form, I'll add the others.
I don't remember this one. What does it mean exactly?
redianthus commentedon Oct 17, 2023
With @chambart we're going to present our freezable/sealable proposal at the next CG meeting.
It allows to have mutable and/or nullable globals/values only during initialization phase and they become immutable and/or non-nullable after this.
It may be one of the things we are proposing.
fitzgen commentedon Oct 17, 2023
Another post-MVP feature to consider would be a way to compare
funcrefs for equality and/or get unique IDs for them or something.Then I could do speculative inlining of
funcrefs as a Wasm-to-Wasm pass in Winliner instead of only forcall_indirects through tables that are never mutated.jakobkummerow commentedon Oct 17, 2023
I agree that this would be useful to have.
Implementation perspective: if we expect that repeated creations of funcrefs for the same function index have distinct identity (in other words, that
(ref.eq (ref.func $x) (ref.func $x))evaluates to0), then that would be annoying/inefficient to implement. If we specify that funcrefs are implicitly cached/canonicalized, i.e. there is only one unique funcref returned by arbitrarily many executions of(ref.func $x)for a given$x, then that would be trivial to implement -- in fact, we already make use of this property (and pointer-equality comparisons based on it) internally in V8.(To be fair, I cannot say with certainty whether other engines might see this differently, but I would find that somewhat surprising: the obvious way how to make
ref.funcfast is to cache or even pre-initialize its result, so it doesn't need an allocation every time.)rossberg commentedon Oct 17, 2023
One of the known problems with function identity is that it invalidates optimisations like specialisation or any code transformation duplicating/merging function definitions that are referenced.
kripken commentedon Oct 17, 2023
Previous discussion on function comparisons: #239 , some use cases and data there from a year ago.
Overall I think this can help in the toolchain, as @fitzgen said, but I also agree with @rossberg that the downsides need to be carefully weighed here. Another thing to consider is that if VMs inline at runtime then this probably becomes less important, and for that reason I don't consider this high priority personally.
fitzgen commentedon Oct 17, 2023
FWIW, not all engines / Wasm environments have (or will ever have) JIT capabilities.
wingo commentedon Aug 6, 2024
For what it is worth, it seems the JS bindings specify that two funcref instances for the same func in the same instance are
eq: https://webassembly.github.io/gc/js-api/index.html#exported-function-exotic-objects. Though, I do understand why Wasm might want to avoid closure equality.Still, for Hoot, I would like to be able to distinguish between different funcrefs; besides specialization, it would be useful for debugging and introspection. All I really need though is to be able to get an i32 associated with the funcref's code.
Perhaps there would be a way to keep funcrefs as non-comparable by default, but allow a module to declare some set of functions as having visible addresses, possibly via designating an element section, where addresses are assigned sequentially starting from 0. Then you could have
func.get_addrretrieve the address for a funcref. If the funcref is not from the current instance (module?) it would return -1 or something. Could this be sufficient for the devirtualization use case?In Hoot probably we have to build something terrible, like putting all funcrefs in a host-side hash table or something. A Wasm facility would be quite welcome.
Edit: Turns out, I need to distinguish between instances; given an open-world system with instances A and B, sequential allocation from 0 within a module doesn't do it. Still working on a solution; I can wrap everything in a struct but that is quite some overhead for a basic ability which is present under the hood (equality and hashing).
rossberg commentedon Aug 8, 2024
@wingo:
Well, the reason for not exposing this is that it in fact may not be present under the hood, e.g., due to optimisations etc.
But yeah, this feature is already listed in the Post-MVP doc.
My preferred mechanism would be something a bit more generic, where we allow type definitions to specify whether references to them support equality or not. For functions, this would allow knowing at definition site whether a function may need to be handled carefully to preserve equality. For structs, defining them as non-eq would essentially give us value types. (I thought this was somewhere in the Post-MVP doc, but apparently I never included it there.)