WebAssembly / interface-types

Other
641 stars 57 forks source link

Instanceof / Upcast equivalent #4

Closed magcius closed 5 years ago

magcius commented 6 years ago

Host bindings, DOM in particular, use subclasses a lot. We would need some ability to do type discrimination. For instance, if I were to receive a DOMEvent object, I would likely want to be able to determine that this is DOMMouseEvent, and be able to call DOMMouseEvent-y things on it.

The details on runtime typechecking in the current proposal are vague (it just says "Throw TypeError (as now) if the wrong type is stored in a Table." but does not elaborate on what "the wrong type" means). Assuming that this is a strict 1:1 type-check, we would need some way to do runtime type discrimination, and a way to cast from one type to another.

Possible idea: a CAST instruction which takes two table indexes src and dest. The instruction checks src instanceof TableType(dest). If the check passes, 1 is pushed to the stack and the object's address copied into dest, so it exists in both tables. Otherwise, 0 is pushed to the stack. Cleanup for both src and dest is left to native code.

A variant of the instruction which takes a table index and a typeidx might also be entertained, in case of if (foo instanceof Type) checks that have no need to access the resulting casted object.

magcius commented 6 years ago

For cases where there is a limited number of host-provided subclasses (e.g. DOMEvent -> DOMMouseEvent), this is implementable in the binding itself (e.g. some host-provided DOMMouseEvent* DOMEvent_as_DOMMouseEvent(DOMEvent*) import generated from WebIDL)

This wouldn't solve cases with union types like HTMLCanvasElement::getContext, but that's already a pretty nasty stretch for WebIDL's type system.

rossberg commented 6 years ago

You seem to suggest adding a JS-specific instruction to Wasm itself. That it is not an option, because Wasm has to remain independent of embeddings. The only option is to import a respective helper from the environment. The host binding framework might provide some aid for doing that.

annevk commented 6 years ago

For the kind of checks IDL does you don't want instanceof btw, you need brand checks as only those work across globals (see also https://github.com/heycam/webidl/issues/97).

magcius commented 6 years ago

I don't think there's anything JS-specific about casting host objects from one kind to another. Perhaps my choice of instanceof wording was poor, but there needs to exist some mechanism to translate DOMEvent* to DOMMouseEvent* and back. My preference is for this be runtime-checkable but we could simply make it trap instead on invalid cast.

If the solution is to generate host functions for every single type pair, that's fine, even if I think it's a bit strange.

lukewagner commented 6 years ago

We have definitely talked about a dynamic cast operator in the context of wasm GC types. If host types (like DOMEvent and DOMMouseEvent) are described as type imports (as previously discussed), then this could mostly fall out for free of the GC feature. Whether a cast from or to a host-type succeeds would, of course, be host defined (just like calling a host import).

However, with just the host binding feature, we don't have first-class reference types. We have talked (in CG meetings, not yet in this proposal) of having a copy_elem opcode which copies from one table element into another (in a same or different table); this is just a basic necessity. If we dropped the restriction that the source/dest tables had to have the exact same element type, that would imply a host-defined check, symmetric to the abovementioned dynamic cast operator.

magcius commented 6 years ago

That works for me. I would also like to propose some way of testing this at runtime. Assuming there are no implicit conversions in copy_elem, a can_copy_elem opcode that takes the same arguments and returns 1 if the equivalent copy_elem can be made and 0 otherwise would be a nice addition.

lukewagner commented 6 years ago

Hmm, interesting. Right, because if a failed conversion traps, and traps are "expensive", a non-trapping query makes sense.

pchickey commented 5 years ago

Closing as out-of-date: these concepts don't map to the current proposal, which has evolved a lot since this issue was opened.