Closed titzer closed 5 years ago
That's a really good point: in the absence of GC data types (or with them turned off), anyref
could be implemented with, e.g., ObjC ARC, maintaining the ability of wasm to operate in a GC-free mode. For browsers, this does still effectively make some amount of wasm GC integration block the Host Binding feature, but OTOH it removes a growing swath of complexity that is essentially working around the lack of an anyref
value type.
So if we only have anyref
, this would lose the static type info that allows efficient calls into WebIDL bindings (avoiding the type check). So presumably we'd also allow references to type imports as value types as well?
Another question is whether, in the web embedding, anyref
would be the same as the WebIDL any which can hold any JS value. This would be necessary to bind to calls that take/return a WebIDL any
.
But with that, it seems like we would avoid:
copy_elem
(assuming we add a cast
operator on anyref
and type imports)set_elem_null
(assuming we add a constant anyref.null
operator)OBJECT_HANDLE
bindingJSON
and STRING
bindings if we can work out an efficient way to get data into and out of linear memory without making an extra copy (maybe some new overloads of JSON.parse
/stringify
and TextDecoder.prototype.decode
that take typed array views)The remaining uses of the binding section would be:
CALL_THIS
etc)U32
STRING_IMMEDIATE
(allows a number of optimizations when calling a WebIDL method)ARRAY_BUFFER
/ TYPED_ARRAY
(since, when calling a WebIDL method, this can avoid creating the view/buffer object at all)A few questions:
anyref
only about opaque host reference types, or about any reference type? e.g. could I make my own anyref and point it at linear memory, or is it just about host things?anyref
? Does client code need to explicitly cast, or would that be implicit?anyref
be null? undefined? false? true? If yes to a value, how can I create an anyref with these values, or check if it is one?@lukewagner That's a good argument about strong types for WebIDL. Worth considering whether imported host types (of representation anyref
) would be substantially different than anyref
alone.
Looking back at https://github.com/WebAssembly/gc/issues/27, I noticed that @DLehenbauer basically proposed this 21 days ago.
@lukewagner I also think we definitely want anyref
to mean reference types only and have a separate any
only to be added later as needed. I imagine that the V8 implementation of any
would use NaN boxing while anyref
would continue to use our current strategy of a SMI tag. Also, any
with a SIMD value might implement a heap allocation...back to madness...
@titzer Yeah, NaN-boxing vs. pointer-to-GC-cell is the same thing I was wondering about. While it seems we'll want any
in the limit, the Host Bindings feature may be viable without it.
@magcius
anyref
would only hold host references; if we keep any
a separate feature as mentioned above, then you wouldn't be able to stick an i32
in anyref
.cast
operator (to a specific type import) and probably an is_null
operator. You make a good point in #4 that a non-trapping "would this cast succeed?" operator would make sense too.anyref
and type imports, if for no other reason than we assume that values have a default value in multiple places (grow_table
, locals, etc).Agreed that supporting anyref would be much better than the ongoing explosion of features for host bindings.
Regarding anyref vs any: I had assumed that the GC extension would eventually allow types like (ref i32) or similar. Semantically, they are references to ints, but an engine could optimise them into tagged ints where applicable. Under this approach, they would naturally inhabit anyref, and so would all JS values. A separate "any" type wouldn't be needed (nor make much sense).
I guess I'm missing something regarding the representation of a separate 'any' type. How could a Wasm engine itself benefit from NaN-boxing when all the bits in a NaN are already observable by Wasm programs? AFAICS an engine would need to box all float values injected into type 'any' anyways.
I think we want to avoid boxing floating point values that are injected into any
, so that would probably mean that a float
-> any
conversion would have to be explicit and do NaN pattern canonicalization.
We considered something similar for exception handling. See some discussion at https://github.com/WebAssembly/exception-handling/issues/30#issuecomment-339510570
There we abandoned this idea because it introduced some thorny lifetime issues. If there's more interest in this kind of feature now, maybe we could also simplify the exception handling proposal.
Closing as out-of-date: these concepts don't map to the current proposal, which has evolved a lot since this issue was opened.
We have a pretty uncontroversial plan to introduce an
anyref
type to WASM in the future. Instead of restricting this type to tables only, what if we also allowanyref
as a WASM value type (not to be stored in linear memory) andtable_get
andtable_set
operations? Ifanyref
remains an opaque type for now (i.e. no new operators), I think this has minimal impact on engine complexity. (For non-JS embedded engines there are implementation strategies that don't require pointer maps, see below*)This could remove a lot of table/slot management complexity, especially for references that never need to be stored into memory, where table/slot management is just overhead. Instead, user code can implement its own WASM wrappers around imports and exports to manage tables and slots so that slot indexes can be stored into the linear memory.
I think this would be more forward-compatible, since I can imagine a world where managed data is dominant and JS/WASM interop is much smoother. In that future world the table bindings would be legacy complexity that we'd probably want to remove.