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

Add first sketch of overview #1

Merged
merged 5 commits into from
Mar 5, 2018
Merged

Add first sketch of overview #1

merged 5 commits into from
Mar 5, 2018

Conversation

rossberg
Copy link
Member

Initial brain dump. Contains most of the ideas, but little of the explanation. :)

- `table.set $x : [i32 t] -> []` iff `t` is the element type of table `$x`
- `table.fill $x : [i32 i32 t] -> []` iff `t` is the element type of table `$x`

* The `call_indirect` instruction takes an additional table index as immediate that identifies the table it calls through.
Copy link
Member

Choose a reason for hiding this comment

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

"additional" sounds like a breaking change; can you nuance to say "the current restriction that the table index immediate must be 0 is removed"?

Copy link
Member Author

Choose a reason for hiding this comment

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

Removed "additional", but note that it is new in both the abstract syntax and the text format.

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, just a few questions:


API extensions:

* Any JS object (non-primitive value) or `null` can be passed as `anyref` to a Wasm function, stored in a global, or in a table.
Copy link
Member

Choose a reason for hiding this comment

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

It would be good to add a TODO to figure out how strings fit in.

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.

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 a subsection on equality and respective notes based on offline discussion -- for now leaving it as a possible extension, since it's not strictly needed and has some repercussions on type imports, even though we will probably want to include it anyway.


Question:

* General function have no reasonable default, do we need scoped variables like `let`?
Copy link
Member

Choose a reason for hiding this comment

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

How would table.grow/Table.prototype.grow work for a table of function references? In general, I wonder if having non-null function references is necessary. E.g., null function references could be implemented without branching as a callable stub (that faults).

Copy link
Member Author

Choose a reason for hiding this comment

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

Good question! I think they both should have an init argument. In the API that defaults to null for backwards compat and convenience.

I added notes to that end.

Copy link
Member

@lukewagner lukewagner Mar 1, 2018

Choose a reason for hiding this comment

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

That makes sense. With the nullable type constructor idea (below), then even host imports or function references could continue to allow a null init argument.

Typing extensions:

* Introduce `anyref`, `anyfunc`, and `nullref` as a new class of *reference types*.
- `reftype ::= anyref | anyfunc | nullref`
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if the nullref type is really necessary. IIUC, having this as a normal value type means we have to handle this degenerate type in locals, globals (and so WebAssembly.Globals) and function signatures. Adding separate "expression" vs. "value" type sets just to avoid these degenerate case would also be additional complexity. Instead of having ref.null producing nullref, I was imagining a null $t which produced the desired reference type $t without any subtyping.

Copy link
Member Author

Choose a reason for hiding this comment

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

It just seemed natural. Can you elaborate in what sense it would introduce a "degenerate" case? AFAICS it falls out for free from the way we will have to uniformly allow for subtyping anyway in all these cases.

Copy link
Member

Choose a reason for hiding this comment

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

If locals, globals, parameters, WebAssembly.Global etc have type nullref; this will actually require a bit of implementation work (extending the call ABI (trivially), deciding how to represent nullref locals (and whether to optimize them to rematerialize null when get_locald or whether to actually store a null value on the stack)) and noone in practice will use nullref for any of these purposes. It seems like a validation detail.

Copy link
Member Author

Choose a reason for hiding this comment

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

Hope you don't mind my questions, but why wouldn't you simply implement them like all reference types? I agree that these cases would be mostly useless in practice, so no need to bother with optimisations or other special casing. AFAICS, the only thing that's strictly necessary is adding one more case to the implementation of ToWebAssemblyValue, which will get several new cases anyway.

For background, another technical reason for having nullref (at least later) is that some things are easier if the subtyping relation forms a lattice, especially when you have structural subtyping on function types (because of contra-variance). There are other places where nullref might come in handy, e.g. as a way to represent nullable types via unions (see comment below).

Anyway, I'm not tied to providing it explicitly, we could just make it an "unnamed" type, i.e., it's part of the validation semantics but you can't use it in declarations. But it feels somewhat incomplete that way.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, we'd just lower it to a reference. But consider the js-types proposal; it'd have to specifically mention "null" and that would look kinda warty. Given the nullable vs. non-nullable types we're talking about separately, considering null to be an operation only available to the nullable ones seems natural.

Also, would nulltype be a suitable bottom of the lattice given the non-nullable reference types?

Copy link
Member Author

Choose a reason for hiding this comment

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

Okay, degraded it to an "internal" type. It's true that the JS API would also want to expose nullref if we made it available, but I'm not sure why that would be a wart. I don't understand your second point; it follows naturally from the subtype relation that ref.null is only available for nullable types.

You are right, nullref wouldn't be the bottom type.

Copy link
Member

Choose a reason for hiding this comment

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

Oops, my second point was w.r.t the alternative proposal to not have a separate nullref type and instead have t.null be an operation for nullable t. But with the other changes, this is a pretty minute detail at this point, so happy to discuss separately and after more experience.


* Do we need to impose constraints on the order of imports, to stratify section dependencies?

* Do we need a nullable `(ref opt $t)` type to allow use with locals etc.?
Copy link
Member

Choose a reason for hiding this comment

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

I definitely think we'll need nullable references for all the things (tables, import signatures, locals). At that point, I wonder whether it's valuable (i.e., a measurable perf improvement when amortized by the overall call-to-JS/DOM) to have non-nullable types. Maybe we could consider non-null types as a later backwards-compatible optimization?

Copy link
Member Author

Choose a reason for hiding this comment

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

Hm, I would expect that in almost all cases other than certain initialisation patterns you don't want null to pollute your reference types, and you want to avoid the cost of an implicit null check for every single access (which may not be free on all architectures).

Copy link
Member

Choose a reason for hiding this comment

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

I was mostly thinking about host types, but I see your point when we get to ref of GC types. For GC types, it seems like there will be large classes of languages which both do and don't have ubiquitous nullable references. Could we have "nullable" be either a type constructor ((nullable (ref $T)))?

Copy link
Member Author

Choose a reason for hiding this comment

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

Possibly, good idea. It's basically the union nullref | ref $T, so a type constructor might work as well.

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 an item on this. Thinking more about it, it's a bit less clear than it would seem at first, see added discussion.

Copy link
Member Author

@rossberg rossberg left a comment

Choose a reason for hiding this comment

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

Added is_null instruction and a section on equality. PTAL

Typing extensions:

* Introduce `anyref`, `anyfunc`, and `nullref` as a new class of *reference types*.
- `reftype ::= anyref | anyfunc | nullref`
Copy link
Member Author

Choose a reason for hiding this comment

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

Okay, degraded it to an "internal" type. It's true that the JS API would also want to expose nullref if we made it available, but I'm not sure why that would be a wart. I don't understand your second point; it follows naturally from the subtype relation that ref.null is only available for nullable types.

You are right, nullref wouldn't be the bottom type.


API extensions:

* Any JS object (non-primitive value) or `null` can be passed as `anyref` to a Wasm function, stored in a global, or in a table.
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 a subsection on equality and respective notes based on offline discussion -- for now leaving it as a possible extension, since it's not strictly needed and has some repercussions on type imports, even though we will probably want to include it anyway.


* Do we need to impose constraints on the order of imports, to stratify section dependencies?

* Do we need a nullable `(ref opt $t)` type to allow use with locals etc.?
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 an item on this. Thinking more about it, it's a bit less clear than it would seem at first, see added discussion.

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.

Thanks for the discussion! Overall, lgtm and happy to merge and discuss details in separate issues.

@rossberg rossberg merged commit 277308d into master Mar 5, 2018
@rossberg rossberg deleted the overview branch March 5, 2018 15:19
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.

None yet

2 participants