Document the new waitqueue design#110
Conversation
Specify the new types and instructions for a waitqueue design that decouples the waitqueue itself from the control word. This is both more geenral and simpler to implement than the previous waitqueue design. Closes #102.
|
Also cc @manoskouk. |
rossberg
left a comment
There was a problem hiding this comment.
Looks right, except for table and memory types.
I'm not too fond of how this overloads the different equality operators. That is quite at odds with having i32.eq, i64.eq, and ref.eq as separate instructions, as well as with the two memory.waitN instructions. I understand that this saves a few opcodes, but wouldn't it be more consistent if we had separate wait32, wait64, and wait_ref variants for all?
| ``` | ||
|
|
||
| Like their linear memory counterparts, the `wait` operations take an expected value and a | ||
| relative timeout in nanoseconds (where negative arguments are interpreted as meaning infinite timeout). |
There was a problem hiding this comment.
| relative timeout in nanoseconds (where negative arguments are interpreted as meaning infinite timeout). | |
| relative timeout in nanoseconds (interpreted as signed, where negative arguments are interpreted as meaning infinite timeout). |
| C |- table.wait x : [(ref null (shared waitqueue)) i32 t i64] -> [i32] | ||
| -- C.tables[x] = shared? table t' | ||
| -- t = wait_expected(t') |
There was a problem hiding this comment.
| C |- table.wait x : [(ref null (shared waitqueue)) i32 t i64] -> [i32] | |
| -- C.tables[x] = shared? table t' | |
| -- t = wait_expected(t') | |
| C |- table.wait x : [(ref null (shared waitqueue)) at t i64] -> [i32] | |
| -- C.tables[x] = shared? table at lim t' | |
| -- t = wait_expected(t') |
| C |- memory.wait32 x : [(ref null (shared waitqueue)) t i32 i64] -> [i32] | ||
| -- C.memories[x] = shared? memory t | ||
|
|
||
| C |- memory.wait64 x : [(ref null (shared waitqueue)) t i64 i64] -> [i32] | ||
| -- C.memories[x] = shared? memory t |
There was a problem hiding this comment.
| C |- memory.wait32 x : [(ref null (shared waitqueue)) t i32 i64] -> [i32] | |
| -- C.memories[x] = shared? memory t | |
| C |- memory.wait64 x : [(ref null (shared waitqueue)) t i64 i64] -> [i32] | |
| -- C.memories[x] = shared? memory t | |
| C |- memory.wait32 x : [(ref null (shared waitqueue)) at i32 i64] -> [i32] | |
| -- C.memories[x] = shared? memory at lim | |
| C |- memory.wait64 x : [(ref null (shared waitqueue)) at i64 i64] -> [i32] | |
| -- C.memories[x] = shared? memory at lim |
It's rather meant to be consistent with things like We could of course just add more instructions if we really wanted to, but I don't see any benefit. |
|
Well, get and set only perform "parametric" reads/writes, they don't inspect or operate on the values themselves (only the _s/u variants do, and they are fixed to a single type). But I agree that cmpxchg is in the same class. We used to have "no overloading" as one of our slogans. That informed a lot of Wasm's design. I'm not sure what to think about dropping that in passing without a wider discussion, and some agreement about where to draw the line in the future. |
|
Fair enough. I'll add a note to this PR for now and add something to the next CG agenda. |
|
No, that's fine. |
jakobkummerow
left a comment
There was a problem hiding this comment.
I'm not a huge fan because I see the "extra flexibility" of this design as unnecessary complexity, but I'm not going to block this if it's what y'all want.
Regarding the "no overloading" question: IMHO the type immediate is enough that I wouldn't consider this overloading. Comparing with Wasm 1.0's arithmetic instructions (such as i32.add vs i64.add), they had no type immediate, so their design could be viewed as "baking in" the type immediate into the one-byte encoding. In a hypothetical alternative where arithmetic ops do have a type immediate, surely there'd only be a single add $t (with $t being one of i32, i64, f32 etc), and nobody would demand having i32.add $t that's invalid if $t != i32 and separately i64.add $t that's invalid if $t != i64 etc. So by analogy, having struct.wait32 $struct $field that's invalid if C.types[$struct][$field] != i32 is likewise a superfluous duplication of the type annotation. The "principal types" property is maintained with just one copy of the type information.
In this particular case the initial instruction already uses a multi-byte sequence for encoding the instruction. So from a naive perspective, this feels like the differences here are really just in the actual encoding (and the text representation) but this doesn't really affect the semantics of Wasm? |
|
@jakobkummerow, @Liedtke, I suggest to continue the discussion on issue #114 that @tlively created. |
Specify the new types and instructions for a waitqueue design that
decouples the waitqueue itself from the control word. This is both
more geenral and simpler to implement than the previous waitqueue
design.
Closes #102.