Skip to content
This repository was archived by the owner on Nov 3, 2021. It is now read-only.

Typed select's return type representation #64

Closed
aheejin opened this issue Nov 19, 2019 · 8 comments
Closed

Typed select's return type representation #64

aheejin opened this issue Nov 19, 2019 · 8 comments

Comments

@aheejin
Copy link
Member

aheejin commented Nov 19, 2019

This proposal introduces a typed select instruction, which takes reference types and also a return type. The return type is written as a vector of valtype. Currently only the vector of length 1 is accepted in the v8 validation. I guess the reason it is a vector is for the multivalue proposal, right?

Is there a reason this has a different representation from that of block, loop, and if type when there are multiple types? blocktype for the multivalue proposal says it is extended to have a type index in the presence of multi values. This will be applied to other instructions such as loops and ifs. Wouldn't it be better for select to be consistent?

cc @tlively

@rossberg
Copy link
Member

See this comment for the rationale behind the format. I honestly don't know what a block type (as introduced by multi-values) would mean for select, since the instruction does not have independent argument and result types, like blocks have.

rossberg pushed a commit that referenced this issue Nov 20, 2019
`memory.init`, `data.drop`, `table.init`, `elem.drop`, `table.copy`

Also fix writing passive segments in the text format.
@tlively
Copy link
Member

tlively commented Nov 20, 2019

Could we enforce in validation that the input types be empty and the output types be whatever would be in the vector today? Or maybe inputs and outputs should be the same. Or maybe the signature should be the full type of the select, including the condition.

Anyway, we can enforce whatever signatures make the most sense. The rationale for doing this is the same as the rationale for disallowing inline multivalue block types, that is deduplication of types and compactness of encoding.

@rossberg
Copy link
Member

rossberg commented Nov 21, 2019

We could, but it would be odd -- for example, then we'd need to artificially introduce the params into the text format, too.

In terms of compactness it wouldn't actually be a win here: most of the cases where it would be a win (single argument) are covered with even less bytes by the existing unannotated select already. And for multi-parameter cases, going through a func type can easily be a net loss rather than a win if it is a one-off use.

And of course, compactness isn't even remotely as relevant for this instruction as it is for blocks, since its frequency of use will almost certainly be in the noise.

(FWIW, I believe we discussed and concluded all this at the A Coruna meeting.)

@tlively
Copy link
Member

tlively commented Nov 21, 2019

Ok, it sounds like there are good reasons for this and I don’t want to needlessly rehash old discussions. Thanks for your explanations!

@aheejin aheejin closed this as completed Nov 21, 2019
@tlively
Copy link
Member

tlively commented Nov 22, 2019

@rossberg I just realized there is another place where we constrain signature types. In the exceptions proposal the event signatures must have empty result types: https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md#event-handling. Does that make enforcing a similar constraint for select sufficiently less odd that we should reconsider it?

@rossberg
Copy link
Member

rossberg commented Nov 23, 2019

Ah, that's a somewhat different story. For events, non-empty result types are reserved and will actually be meaningful with future extensions for resumable exceptions / effect handlers / coroutines / stack switching (I plan to present more concrete ideas at the Feb meeting). So that's more like the situation with block signatures.

@bitwalker
Copy link

@rossberg Do you have any notes or anything about what you have in mind for coroutines/stack switching? I'm most interested in whether or not the coroutine primitives would be designed around stackful coroutines, or stackless coroutines. Presumably the presence of stack switching primitives would allow for the former, so I guess even if the coroutine primitives are stackless, having the stack switching primitives would be enough to do what I need.

If you recall we had some discussion on an issue earlier this year about coroutines/continuations, but there was no immediate plans to support anything like that, other than the possibility that resumable exceptions might provide a way to implement a form of delimited continuations; and the lack of appropriate stack primitives meant neither coroutines nor continuations could be implemented from the ground up either. If that is something that will change in the the coming year, that would be fantastic! I definitely would be interested in helping move that work forward, if I can be of assistance.

@rossberg
Copy link
Member

@bitwalker, nothing I can currently point to, sorry. But yes, the goal here is to provide a "stack switching" primitive, so in C++ terminology, it would be "stackful" coroutines. AFAICS, "stackless" pseudo coroutines aren't all that interesting for Wasm, since a producer can implement them themselves via a fairly local program transformation.

The more interesting distinction is between symmetric and asymmetric coroutines, and this would be the latter.

Roughly, the idea is a new reference type cont $ft of continuations (a.k.a. stacks), where $ft is a function type, along with respective instructions cont.new, cont.yield, cont.resume, and a few more. Unlike more conventional coroutines, the continuation type allows passing values back and forth between yield and resume points. But this has to be typed properly in Wasm, and that's where event declarations come in: yield generates an event with a certain type and passes along its arguments (like throw). It can only be resumed by passing back the event's results (adopting ideas from effect handlers). Like exceptions and their exn values, events are captured as first-class values of a type evt, so that resumption can happen even after the parent has returned.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants