Skip to content
This repository was archived by the owner on Apr 25, 2025. It is now read-only.

Add explicit RTT support for casts #38

Merged
merged 4 commits into from
Oct 15, 2018
Merged

Add explicit RTT support for casts #38

merged 4 commits into from
Oct 15, 2018

Conversation

rossberg
Copy link
Member

@rossberg rossberg commented Oct 7, 2018

This came out of the discussion on PR #34.

Also, add more motivating explanation in overview.

@rossberg rossberg requested a review from lukewagner October 7, 2018 01:56
}
```

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.

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).

Copy link
Member Author

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.

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.

Copy link
Member

@lukewagner lukewagner left a 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.

@@ -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>`
Copy link
Member

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 ;)

Copy link
Member Author

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.

@@ -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
Copy link
Member

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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

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:
Copy link
Member

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/

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

@rossberg rossberg merged commit f51f3ae into master Oct 15, 2018
@rossberg rossberg deleted the rtt branch October 15, 2018 17:41
@rossberg rossberg restored the rtt branch October 15, 2018 22:12
rossberg pushed a commit that referenced this pull request Feb 24, 2021
Increase the table count limit to 100,000
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants