-
Notifications
You must be signed in to change notification settings - Fork 4
Revamp the overview with new insights #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, @RossTate! I haven't read all the way through yet, but here are a few initial comments.
[Transitioning from Structural to Nominal Code with Efficient Gradual Typing](https://www.cs.cornell.edu/~ross/publications/monnom/monnom-oopsla21.pdf) implemented call tags in LLVM by fixing an argument size used by all call tags. | ||
If a call tag's arity exceeded the argument size, then the remaining arguments were stored on the stack, and the last argument was instead a pointer to this stack-allocated tuple. | ||
It is unknown what the overhead of this approach to large-arity call tags is, because for their experiments no call tag's arity exceeded the fixed argument size. | ||
They did however measure the overhead of this LLVM-compilation approach for small-arity call tags compared to using typed function references, and they found that there was *no* overhead. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be clear, the typed function references in this experiment were in a non-Wasm context, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct. They were LLVM's function-typed pointers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you concerned that these observations would not carry over to WebAssembly? If so, could you articulate why? (I can see observations not carrying over in the reverse direction due to the intrinsic overheads currently in WebAssembly, but I'm having a hard time seeing why observations wouldn't carry over in this direction.)
|
||
## Extension: Fall-Back Handlers | ||
`call_tag.canon` is restricted to providing a canonical call tag for all "concrete" types, such as primitives or imported concrete nominal types (like `$java.lang.String`). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not clear on how it knows what imported types are abstract vs concrete. Is this something I'm forgetting out of the type imports proposal?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this abstract vs concrete import concept is just floating around right now. See WebAssembly/gc#241 (comment) and WebAssembly/gc#241 (comment) for more on it.
|
||
Many call tags are specialized/optimized cases of more generic call tags. | ||
In these cases, it can be useful to pass the `funcref` that didn't recognize the call tag to the fall-back handler so that a specialized call tag can simply call the same `funcref` with the more generic call tag. | ||
Call tags make it unnecessary for `funcref`s to have casting infrastructure, and they make the type-checking complexity of first-class function types unnecessary (which prior works in this space have found to be problematic). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not to ask for cherries on top, but it would be lovely to see this and the next section elaborated at some point, specifically the references to prior works here and the lack of support in typed function references below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately this issue isn't discussed in the prior works; it's just folklore amongst authors of works in this space (which I happen to be among and so privy to). In short, the contravariance of code pointers makes them a big pain, and all people do is get them from some global and put them in a v-table or get them from some v-table, keep them in some register, and then call them. You don't see fancy things like use a branch to pick between two function pointers, which you do see with other types plenty, so it's a lot of complexity to add for very simple use cases.
👍 |
This addresses the request in #5 for more discussion of performance, while also doing a major overhaul of the overview to incorporate insights gained from recent explorations and experiments.
@tlively, would you be able to give this a look at some point? I'd gladly incorporate any suggestions you have on making it more accessible or adding clarifications/background and the like.