-
Notifications
You must be signed in to change notification settings - Fork 74
Add explicit RTT support for casts #38
Conversation
} | ||
``` | ||
|
||
Here, `make_pair` as well as `fst` and `snd` need to be able to operate on any type of pair. Furthermore, `fst` and `snd` cannot simply be type-specialised at compile time, because that would be insufficient to compile `g`, which takes a polymorphic function as an argument and instantiates it with multiple different types. Such *first-class* polymorphism is not expressible with compile time techniques such as C++ templates, but common-place in many languages (including OO ones like Java or C#, where it can be emulated via generic methods). Untyped languages like JavaScript or Scheme trivially allow such programs as well. |
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 think this could be explained more precisely. In particular, there will be programming languages for which the type checker is able to determine the return type of the use of pick
in g
, and thus can compile it to safe code that does not need a cast_down
(e.g. when translated directly to LLVM, C or x86). So the need for a RTT / cast_down
is not just about first class polymorphism, but it is about a mismatch between the language and what wasm types can express (since we apparently don't want to have the concept of statically typed generics at the wasm level). This a tradeoff we're choosing, i.e. we could instead decide to make wasm types a whole lot more complicated in exchange for needing less or no cast_down
ops or need for a RTT field in all "objects".
This is similar to what Java does, which I am not a fan of, though I understand why dealing with generics at the wasm level may not be impractical. On a related note, letting inefficiencies like this creep into the format we're encouraging engines to do their own type analysis to omit cast_down
and RTT fields where possible (it wouldn't surprise me if Hotspot does this already).
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.
@aardappel, I agree that this is a choice we make. I added a couple more sentences mentioning the possible future addition of type parameters to Wasm to avoid this overhead.
To be clear, the problem isn't the ability to deduce the return type -- AFAICT, all languages are able to do that (that's the point of generics after all). The problem is that the compilation of fst
and snd
itself must not depend on that type because you generally cannot tell, at compile time, the set of all types they will be instantiated with (static analysis can do that in many cases but not all). So compile-time type specialisation does not generally work with first-class polymorphism. Unless you are willing to implement runtime compilation and type specialisation (like C# / .NET) you have to rely on a type-agnostic compilation scheme, and short of having type parameters in Wasm, going to the top type and casting back is the only alternative available.
Added a version of this as explanation.
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.
Ah, good point about fst
and snd
, thanks. Good to hear you think type parameters could still be added in the future.
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.
Overall, looks great, thanks.
proposals/gc/MVP.md
Outdated
@@ -27,6 +27,10 @@ Based on [reference types proposal](https://github.com/WebAssembly/reference-typ | |||
* `i31ref` is a new reference type | |||
- `reftype ::= ... | i31ref` | |||
|
|||
* `rtt <reftype>` is a new reference type that is a runtime representation of type `<reftype>` |
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.
nit: maybe add a link here to Overview.md#casting-and-runtime-types?
Also, not to bikeshed but: are these really "runtime representions of types" (which one might assume are unique/unified, contain information about the type, and/or are closely tied to an object's complete type), or are they just "tags" which represent a capability to downcast (and are exception tags still called tags)? Either way the acronym stays the same ;)
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.
Added link.
I think both views are valid. You could also call them runtime type tags. :) However, in their role as target types for casts they aren't really tagging anything, so I have a slight preference for calling them (nominal) types, even though they are abstract and only contain information about their supertype relation.
proposals/gc/MVP.md
Outdated
@@ -122,6 +129,10 @@ In addition to the rules for basic reference types: | |||
- `var <valtype> <: var <valtype>` | |||
- Note: mutable fields are *not* subtypes of immutable ones, so `const` really means constant, not read-only | |||
|
|||
* `rtt t` is a subtype of `anyref` | |||
- `rtt t <: anyref` | |||
- Note: `rtt t1` is *not* a subtype of `rtt t2`, even if `t1` is a subtype of `t2`; such subtyping would be unsound, since RTTs are used in both co- and contravariant roles |
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 had to go hunting for the contravariant case that would break if this was allowed. Is it only struct.new_rtt
? If so, it'd be friendly to future readers to just name this one case and why it's a problem.
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.
Done.
proposals/gc/Overview.md
Outdated
A runtime type is an expression of type `rtt <type>`, which is another form of opaque reference type. It denotes the static type `<type>`. | ||
|
||
Runtime type checks verify the subtype relation between runtime types. | ||
In order to make these checks cheap, runtime subtyping follows a *nominal* semantics. To that and, every RTT value not only represents a given type, it also records a subtype relation to another (runtime) type (possibly `anyref`) defined when constructing the RTT value: |
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.
nit: s/To that and/To that end/
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.
Fixed.
Increase the table count limit to 100,000
This came out of the discussion on PR #34.
Also, add more motivating explanation in overview.