WebAssembly / shared-everything-threads

A draft proposal for spawning threads in WebAssembly
Other
29 stars 1 forks source link

Should `table.atomic.{get,set,rmw.xchg}` work for funcref/externref tables? #31

Closed alexcrichton closed 5 months ago

alexcrichton commented 5 months ago

Currently the explainer says "valid for anyref tables" which I believe doesn't include other "top" types like externref and funcref. Is it the intention that these instructions work for funcref/externref as well though?

I can see how cmpxchg shouldn't work with funcref/externref, however, hence the limitation to eqref, so this is just about the get/set/xchg instructions.

tlively commented 5 months ago

Good question! The wording limiting atomic operations to anyref (or (ref null (shared any) of course) and its subtypes is intentional, under the assumption that engines might represent other types in a way that would not allow lock-free atomic accesses. For example I believe wasmtime was at some point using fat pointers for functions (is that right?) and I know wasm2c uses an extremely large representation for exnref. This is similar to how we don't provide atomic accesses to v128 types.

If that makes sense to everyone, I can add a note clarifying the intent to the text.

alexcrichton commented 5 months ago

Ah ok that sounds good! I don't have a use case in mind for supporting this but I mistakenly assumed that the intention was to support atomic operations on tables. In that sense I think it'd be good to have a clarification. Wasmtime currently has a pointer-per-funcref but we've considered moving to a flatter representation (as you mention) but we haven't made the transition yet and I was thinking about that when reading over this.

Thinking a bit more on this though, the intention is that table.{get,set} still work on shared tables, right? If so engines with larger-than-pointer-size representations will still need to somehow rationalize what it means to concurrently table.{get,set}. For example we wouldn't want a table.get to produce a "half and half" funcref if it were to race with a table.set. Mostly I say this in the sense that the omission of these atomic instructions for funcref, for example, does not mean that engines can completely ignore the concurrent behavior here I think. There will still need to be some sort of atomic handling in place to handle larger-than-pointer-width funcrefs/externrefs/exnrefs I think

tlively commented 5 months ago

Good point, we'll still need to spec that even non-synchronizing accesses to references should never tear. In practice that might mean a performance hit for accessing shared tables or globals for some types.

conrad-watt commented 5 months ago

Good point, we'll still need to spec that even non-synchronizing accesses to references should never tear. In practice that might mean a performance hit for accessing shared tables or globals for some types.

The reasonable strategies I can think of to avoid tearing on large representations also seem like they would support atomic accesses. I'm fine with being conservative for now but it's worth thinking about whether we'll want to relax our anyref restriction in future.